mirror of
https://github.com/minetest-mods/irc.git
synced 2024-12-23 23:40:20 +01:00
initial commit
This commit is contained in:
commit
dfab9bbcd4
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
Build
|
||||
irc-*
|
13
CMakeLists.txt
Normal file
13
CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
# :mode=cmake:noTabs=true:tabSize=4:
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
project(MINETEST_IRC C)
|
||||
|
||||
set(MINETEST_IRC_VERSION 0.1.0)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/lua)
|
||||
|
||||
add_subdirectory(src)
|
69
README.txt
Normal file
69
README.txt
Normal file
@ -0,0 +1,69 @@
|
||||
|
||||
IRC Mod for Minetest
|
||||
(C) 2012 Diego Martínez <kaeza@users.sf.net>
|
||||
|
||||
INTRODUCTION
|
||||
------------
|
||||
This mod is just a glue between luasocket, LuaIRC, and Minetest. It
|
||||
provides a two-way communication between the in-game chat, and an
|
||||
arbitrary IRC channel.
|
||||
|
||||
Note: This mod is currently a work-in-progress, and is only tested under
|
||||
Ubuntu 12.04 with Minetest 0.4.3 and 0.4.4-dev. Testers for other
|
||||
platforms are welcome.
|
||||
|
||||
|
||||
INSTALLING
|
||||
----------
|
||||
Unpack the archive and put the `irc' directory in any of the directories
|
||||
where Minetest looks for mods. For more information, see:
|
||||
http://wiki.minetest.net/wiki/Installing_mods
|
||||
|
||||
|
||||
SETTINGS
|
||||
--------
|
||||
All settings are changed directly in the script. If any of these settings
|
||||
are either nil or false, the default value is used.
|
||||
|
||||
SERVER (string, default "irc.freenode.net")
|
||||
This is the IRC server the mod connects to.
|
||||
|
||||
CHANNEL (string, default "#minetest-irc-testing")
|
||||
The IRC channel to join.
|
||||
|
||||
DTIME (number, default 0.2)
|
||||
This is the time in seconds between updates in the connection.
|
||||
In order not to block the game, the mod must periodically "poll"
|
||||
the connection to both send messages to, and receive messages
|
||||
from the channel. A high value means slower connection to IRC,
|
||||
but possibly better response from the game. A low value means
|
||||
the mod "polls" the connection more often, but can make the
|
||||
game hang. It allows fractional values.
|
||||
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
This license applies only to my code (in init.lua).
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
The files `http.lua', `ltn12.lua', `mime.lua', `smtp.lua', `socket.lua',
|
||||
and `url.lua' are part of the luasocket project
|
||||
(http://luasocket.luaforge.org/). See `LICENSE-luasocket.txt' for
|
||||
licensing information.
|
||||
|
||||
The `irc.lua' file and the entire content of the `irc' directory are part
|
||||
of the LuaIRC project (http://luairc.luaforge.org/). See
|
||||
`LICENSE-LuaIRC.txt' for licensing information.
|
6189
doc/cmake.html
Normal file
6189
doc/cmake.html
Normal file
File diff suppressed because one or more lines are too long
405
doc/lua/contents.html
Normal file
405
doc/lua/contents.html
Normal file
@ -0,0 +1,405 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Lua 5.1 reference manual - contents</TITLE>
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
|
||||
</HEAD>
|
||||
|
||||
<BODY BGCOLOR="#FFFFFF">
|
||||
|
||||
<HR>
|
||||
<H1>
|
||||
<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua" BORDER=0></A>
|
||||
Lua 5.1 Reference Manual
|
||||
</H1>
|
||||
|
||||
<SMALL>
|
||||
<A HREF="http://www.lua.org/copyright.html">Copyright</A>
|
||||
© 2006 Lua.org, PUC-Rio. All rights reserved.
|
||||
</SMALL>
|
||||
<HR>
|
||||
|
||||
<H2>Contents</H2>
|
||||
<UL>
|
||||
<LI><A HREF="#quick">Quick index</A>
|
||||
<P>
|
||||
<LI><A HREF="manual.html">Top</A>
|
||||
<LI><A HREF="manual.html#1">1 - Introduction</A>
|
||||
<LI><A HREF="manual.html#2">2 - The Language</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#2.1">2.1 - Lexical Conventions</A>
|
||||
<LI><A HREF="manual.html#2.2">2.2 - Values and Types</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#2.2.1">2.2.1 - Coercion</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#2.3">2.3 - Variables</A>
|
||||
<LI><A HREF="manual.html#2.4">2.4 - Statements</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#2.4.1">2.4.1 - Chunks</A>
|
||||
<LI><A HREF="manual.html#2.4.2">2.4.2 - Blocks</A>
|
||||
<LI><A HREF="manual.html#2.4.3">2.4.3 - Assignment</A>
|
||||
<LI><A HREF="manual.html#2.4.4">2.4.4 - Control Structures</A>
|
||||
<LI><A HREF="manual.html#2.4.5">2.4.5 - For Statement</A>
|
||||
<LI><A HREF="manual.html#2.4.6">2.4.6 - Function Calls as Statements</A>
|
||||
<LI><A HREF="manual.html#2.4.7">2.4.7 - Local Declarations</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#2.5">2.5 - Expressions</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#2.5.1">2.5.1 - Arithmetic Operators</A>
|
||||
<LI><A HREF="manual.html#2.5.2">2.5.2 - Relational Operators</A>
|
||||
<LI><A HREF="manual.html#2.5.3">2.5.3 - Logical Operators</A>
|
||||
<LI><A HREF="manual.html#2.5.4">2.5.4 - Concatenation</A>
|
||||
<LI><A HREF="manual.html#2.5.5">2.5.5 - The Length Operator</A>
|
||||
<LI><A HREF="manual.html#2.5.6">2.5.6 - Precedence</A>
|
||||
<LI><A HREF="manual.html#2.5.7">2.5.7 - Table Constructors</A>
|
||||
<LI><A HREF="manual.html#2.5.8">2.5.8 - Function Calls</A>
|
||||
<LI><A HREF="manual.html#2.5.9">2.5.9 - Function Definitions</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#2.6">2.6 - Visibility Rules</A>
|
||||
<LI><A HREF="manual.html#2.7">2.7 - Error Handling</A>
|
||||
<LI><A HREF="manual.html#2.8">2.8 - Metatables</A>
|
||||
<LI><A HREF="manual.html#2.9">2.9 - Environments</A>
|
||||
<LI><A HREF="manual.html#2.10">2.10 - Garbage Collection</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#2.10.1">2.10.1 - Garbage-Collection Metamethods</A>
|
||||
<LI><A HREF="manual.html#2.10.2">2.10.2 - Weak Tables</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#2.11">2.11 - Coroutines</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#3">3 - The Application Program Interface</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#3.1">3.1 - The Stack</A>
|
||||
<LI><A HREF="manual.html#3.2">3.2 - Stack Size</A>
|
||||
<LI><A HREF="manual.html#3.3">3.3 - Pseudo-Indices</A>
|
||||
<LI><A HREF="manual.html#3.4">3.4 - C Closures</A>
|
||||
<LI><A HREF="manual.html#3.5">3.5 - Registry</A>
|
||||
<LI><A HREF="manual.html#3.6">3.6 - Error Handling in C</A>
|
||||
<LI><A HREF="manual.html#3.7">3.7 - Functions and Types</A>
|
||||
<LI><A HREF="manual.html#3.8">3.8 - The Debug Interface</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#4">4 - The Auxiliary Library</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#4.1">4.1 - Functions and Types</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#5">5 - Standard Libraries</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#5.1">5.1 - Basic Functions</A>
|
||||
<LI><A HREF="manual.html#5.2">5.2 - Coroutine Manipulation</A>
|
||||
<LI><A HREF="manual.html#5.3">5.3 - Modules</A>
|
||||
<LI><A HREF="manual.html#5.4">5.4 - String Manipulation</A>
|
||||
<LI><A HREF="manual.html#5.5">5.5 - Table Manipulation</A>
|
||||
<LI><A HREF="manual.html#5.6">5.6 - Mathematical Functions</A>
|
||||
<LI><A HREF="manual.html#5.7">5.7 - Input and Output Facilities</A>
|
||||
<LI><A HREF="manual.html#5.8">5.8 - Operating System Facilities</A>
|
||||
<LI><A HREF="manual.html#5.9">5.9 - The Debug Library</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#6">6 - Lua Stand-alone</A>
|
||||
<LI><A HREF="manual.html#incompat">Incompatibilities with the Previous Version</A>
|
||||
<LI><A HREF="manual.html#BNF">The Complete Syntax of Lua</A>
|
||||
|
||||
</UL>
|
||||
|
||||
<H2><A NAME="quick">Quick index</A></H2>
|
||||
<TABLE>
|
||||
<TR VALIGN="top">
|
||||
<TD WIDTH="35%">
|
||||
<H3><A NAME="functions">Functions</A></H3>
|
||||
<A HREF="manual.html#pdf-_G">_G</A><BR>
|
||||
<A HREF="manual.html#pdf-_VERSION">_VERSION</A><BR>
|
||||
<A HREF="manual.html#pdf-assert">assert</A><BR>
|
||||
<A HREF="manual.html#pdf-collectgarbage">collectgarbage</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.create">coroutine.create</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.resume">coroutine.resume</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.running">coroutine.running</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.status">coroutine.status</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.wrap">coroutine.wrap</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.yield">coroutine.yield</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.debug">debug.debug</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getfenv">debug.getfenv</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.gethook">debug.gethook</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getinfo">debug.getinfo</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getlocal">debug.getlocal</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getmetatable">debug.getmetatable</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getregistry">debug.getregistry</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getupvalue">debug.getupvalue</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.setfenv">debug.setfenv</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.sethook">debug.sethook</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.setlocal">debug.setlocal</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.setmetatable">debug.setmetatable</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.setupvalue">debug.setupvalue</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.traceback">debug.traceback</A><BR>
|
||||
<A HREF="manual.html#pdf-dofile">dofile</A><BR>
|
||||
<A HREF="manual.html#pdf-error">error</A><BR>
|
||||
<A HREF="manual.html#pdf-file:close">file:close</A><BR>
|
||||
<A HREF="manual.html#pdf-file:flush">file:flush</A><BR>
|
||||
<A HREF="manual.html#pdf-file:lines">file:lines</A><BR>
|
||||
<A HREF="manual.html#pdf-file:read">file:read</A><BR>
|
||||
<A HREF="manual.html#pdf-file:seek">file:seek</A><BR>
|
||||
<A HREF="manual.html#pdf-file:setvbuf">file:setvbuf</A><BR>
|
||||
<A HREF="manual.html#pdf-file:write">file:write</A><BR>
|
||||
<A HREF="manual.html#pdf-getfenv">getfenv</A><BR>
|
||||
<A HREF="manual.html#pdf-getmetatable">getmetatable</A><BR>
|
||||
<A HREF="manual.html#pdf-io.close">io.close</A><BR>
|
||||
<A HREF="manual.html#pdf-io.flush">io.flush</A><BR>
|
||||
<A HREF="manual.html#pdf-io.input">io.input</A><BR>
|
||||
<A HREF="manual.html#pdf-io.lines">io.lines</A><BR>
|
||||
<A HREF="manual.html#pdf-io.open">io.open</A><BR>
|
||||
<A HREF="manual.html#pdf-io.output">io.output</A><BR>
|
||||
<A HREF="manual.html#pdf-io.popen">io.popen</A><BR>
|
||||
<A HREF="manual.html#pdf-io.read">io.read</A><BR>
|
||||
<A HREF="manual.html#pdf-io.tmpfile">io.tmpfile</A><BR>
|
||||
<A HREF="manual.html#pdf-io.type">io.type</A><BR>
|
||||
<A HREF="manual.html#pdf-io.write">io.write</A><BR>
|
||||
<A HREF="manual.html#pdf-ipairs">ipairs</A><BR>
|
||||
<A HREF="manual.html#pdf-load">load</A><BR>
|
||||
<A HREF="manual.html#pdf-loadfile">loadfile</A><BR>
|
||||
<A HREF="manual.html#pdf-loadstring">loadstring</A><BR>
|
||||
<A HREF="manual.html#pdf-math.abs">math.abs</A><BR>
|
||||
<A HREF="manual.html#pdf-math.acos">math.acos</A><BR>
|
||||
<A HREF="manual.html#pdf-math.asin">math.asin</A><BR>
|
||||
<A HREF="manual.html#pdf-math.atan2">math.atan2</A><BR>
|
||||
<A HREF="manual.html#pdf-math.atan">math.atan</A><BR>
|
||||
<A HREF="manual.html#pdf-math.ceil">math.ceil</A><BR>
|
||||
<A HREF="manual.html#pdf-math.cosh">math.cosh</A><BR>
|
||||
<A HREF="manual.html#pdf-math.cos">math.cos</A><BR>
|
||||
<A HREF="manual.html#pdf-math.deg">math.deg</A><BR>
|
||||
<A HREF="manual.html#pdf-math.exp">math.exp</A><BR>
|
||||
<A HREF="manual.html#pdf-math.floor">math.floor</A><BR>
|
||||
<A HREF="manual.html#pdf-math.fmod">math.fmod</A><BR>
|
||||
<A HREF="manual.html#pdf-math.frexp">math.frexp</A><BR>
|
||||
<A HREF="manual.html#pdf-math.ldexp">math.ldexp</A><BR>
|
||||
<A HREF="manual.html#pdf-math.log10">math.log10</A><BR>
|
||||
<A HREF="manual.html#pdf-math.log">math.log</A><BR>
|
||||
<A HREF="manual.html#pdf-math.max">math.max</A><BR>
|
||||
<A HREF="manual.html#pdf-math.min">math.min</A><BR>
|
||||
<A HREF="manual.html#pdf-math.modf">math.modf</A><BR>
|
||||
<A HREF="manual.html#pdf-math.pow">math.pow</A><BR>
|
||||
<A HREF="manual.html#pdf-math.rad">math.rad</A><BR>
|
||||
<A HREF="manual.html#pdf-math.random">math.random</A><BR>
|
||||
<A HREF="manual.html#pdf-math.randomseed">math.randomseed</A><BR>
|
||||
<A HREF="manual.html#pdf-math.sinh">math.sinh</A><BR>
|
||||
<A HREF="manual.html#pdf-math.sin">math.sin</A><BR>
|
||||
<A HREF="manual.html#pdf-math.sqrt">math.sqrt</A><BR>
|
||||
<A HREF="manual.html#pdf-math.tanh">math.tanh</A><BR>
|
||||
<A HREF="manual.html#pdf-math.tan">math.tan</A><BR>
|
||||
<A HREF="manual.html#pdf-module">module</A><BR>
|
||||
<A HREF="manual.html#pdf-next">next</A><BR>
|
||||
<A HREF="manual.html#pdf-os.clock">os.clock</A><BR>
|
||||
<A HREF="manual.html#pdf-os.date">os.date</A><BR>
|
||||
<A HREF="manual.html#pdf-os.difftime">os.difftime</A><BR>
|
||||
<A HREF="manual.html#pdf-os.execute">os.execute</A><BR>
|
||||
<A HREF="manual.html#pdf-os.exit">os.exit</A><BR>
|
||||
<A HREF="manual.html#pdf-os.getenv">os.getenv</A><BR>
|
||||
<A HREF="manual.html#pdf-os.remove">os.remove</A><BR>
|
||||
<A HREF="manual.html#pdf-os.rename">os.rename</A><BR>
|
||||
<A HREF="manual.html#pdf-os.setlocale">os.setlocale</A><BR>
|
||||
<A HREF="manual.html#pdf-os.time">os.time</A><BR>
|
||||
<A HREF="manual.html#pdf-os.tmpname">os.tmpname</A><BR>
|
||||
<A HREF="manual.html#pdf-package.cpath">package.cpath</A><BR>
|
||||
<A HREF="manual.html#pdf-package.loaded">package.loaded</A><BR>
|
||||
<A HREF="manual.html#pdf-package.loadlib">package.loadlib</A><BR>
|
||||
<A HREF="manual.html#pdf-package.path">package.path</A><BR>
|
||||
<A HREF="manual.html#pdf-package.preload">package.preload</A><BR>
|
||||
<A HREF="manual.html#pdf-package.seeall">package.seeall</A><BR>
|
||||
<A HREF="manual.html#pdf-pairs">pairs</A><BR>
|
||||
<A HREF="manual.html#pdf-pcall">pcall</A><BR>
|
||||
<A HREF="manual.html#pdf-print">print</A><BR>
|
||||
<A HREF="manual.html#pdf-rawequal">rawequal</A><BR>
|
||||
<A HREF="manual.html#pdf-rawget">rawget</A><BR>
|
||||
<A HREF="manual.html#pdf-rawset">rawset</A><BR>
|
||||
<A HREF="manual.html#pdf-require">require</A><BR>
|
||||
<A HREF="manual.html#pdf-select">select</A><BR>
|
||||
<A HREF="manual.html#pdf-setfenv">setfenv</A><BR>
|
||||
<A HREF="manual.html#pdf-setmetatable">setmetatable</A><BR>
|
||||
<A HREF="manual.html#pdf-string.byte">string.byte</A><BR>
|
||||
<A HREF="manual.html#pdf-string.char">string.char</A><BR>
|
||||
<A HREF="manual.html#pdf-string.dump">string.dump</A><BR>
|
||||
<A HREF="manual.html#pdf-string.find">string.find</A><BR>
|
||||
<A HREF="manual.html#pdf-string.format">string.format</A><BR>
|
||||
<A HREF="manual.html#pdf-string.gmatch">string.gmatch</A><BR>
|
||||
<A HREF="manual.html#pdf-string.gsub">string.gsub</A><BR>
|
||||
<A HREF="manual.html#pdf-string.len">string.len</A><BR>
|
||||
<A HREF="manual.html#pdf-string.lower">string.lower</A><BR>
|
||||
<A HREF="manual.html#pdf-string.match">string.match</A><BR>
|
||||
<A HREF="manual.html#pdf-string.rep">string.rep</A><BR>
|
||||
<A HREF="manual.html#pdf-string.reverse">string.reverse</A><BR>
|
||||
<A HREF="manual.html#pdf-string.sub">string.sub</A><BR>
|
||||
<A HREF="manual.html#pdf-string.upper">string.upper</A><BR>
|
||||
<A HREF="manual.html#pdf-table.concat">table.concat</A><BR>
|
||||
<A HREF="manual.html#pdf-table.insert">table.insert</A><BR>
|
||||
<A HREF="manual.html#pdf-table.maxn">table.maxn</A><BR>
|
||||
<A HREF="manual.html#pdf-table.remove">table.remove</A><BR>
|
||||
<A HREF="manual.html#pdf-table.sort">table.sort</A><BR>
|
||||
<A HREF="manual.html#pdf-tonumber">tonumber</A><BR>
|
||||
<A HREF="manual.html#pdf-tostring">tostring</A><BR>
|
||||
<A HREF="manual.html#pdf-type">type</A><BR>
|
||||
<A HREF="manual.html#pdf-unpack">unpack</A><BR>
|
||||
<A HREF="manual.html#pdf-xpcall">xpcall</A><BR>
|
||||
|
||||
</TD>
|
||||
<TD>
|
||||
<H3>API</H3>
|
||||
<A HREF="manual.html#lua_Alloc">lua_Alloc</A><BR>
|
||||
<A HREF="manual.html#lua_CFunction">lua_CFunction</A><BR>
|
||||
<A HREF="manual.html#lua_Debug">lua_Debug</A><BR>
|
||||
<A HREF="manual.html#lua_Hook">lua_Hook</A><BR>
|
||||
<A HREF="manual.html#lua_Integer">lua_Integer</A><BR>
|
||||
<A HREF="manual.html#lua_Number">lua_Number</A><BR>
|
||||
<A HREF="manual.html#lua_Reader">lua_Reader</A><BR>
|
||||
<A HREF="manual.html#lua_State">lua_State</A><BR>
|
||||
<A HREF="manual.html#lua_Writer">lua_Writer</A><BR>
|
||||
<A HREF="manual.html#lua_atpanic">lua_atpanic</A><BR>
|
||||
<A HREF="manual.html#lua_call">lua_call</A><BR>
|
||||
<A HREF="manual.html#lua_checkstack">lua_checkstack</A><BR>
|
||||
<A HREF="manual.html#lua_close">lua_close</A><BR>
|
||||
<A HREF="manual.html#lua_concat">lua_concat</A><BR>
|
||||
<A HREF="manual.html#lua_cpcall">lua_cpcall</A><BR>
|
||||
<A HREF="manual.html#lua_createtable">lua_createtable</A><BR>
|
||||
<A HREF="manual.html#lua_dump">lua_dump</A><BR>
|
||||
<A HREF="manual.html#lua_equal">lua_equal</A><BR>
|
||||
<A HREF="manual.html#lua_error">lua_error</A><BR>
|
||||
<A HREF="manual.html#lua_gc">lua_gc</A><BR>
|
||||
<A HREF="manual.html#lua_getallocf">lua_getallocf</A><BR>
|
||||
<A HREF="manual.html#lua_getfenv">lua_getfenv</A><BR>
|
||||
<A HREF="manual.html#lua_getfield">lua_getfield</A><BR>
|
||||
<A HREF="manual.html#lua_getglobal">lua_getglobal</A><BR>
|
||||
<A HREF="manual.html#lua_gethook">lua_gethook</A><BR>
|
||||
<A HREF="manual.html#lua_gethookcount">lua_gethookcount</A><BR>
|
||||
<A HREF="manual.html#lua_gethookmask">lua_gethookmask</A><BR>
|
||||
<A HREF="manual.html#lua_getinfo">lua_getinfo</A><BR>
|
||||
<A HREF="manual.html#lua_getlocal">lua_getlocal</A><BR>
|
||||
<A HREF="manual.html#lua_getmetatable">lua_getmetatable</A><BR>
|
||||
<A HREF="manual.html#lua_getstack">lua_getstack</A><BR>
|
||||
<A HREF="manual.html#lua_gettable">lua_gettable</A><BR>
|
||||
<A HREF="manual.html#lua_gettop">lua_gettop</A><BR>
|
||||
<A HREF="manual.html#lua_getupvalue">lua_getupvalue</A><BR>
|
||||
<A HREF="manual.html#lua_insert">lua_insert</A><BR>
|
||||
<A HREF="manual.html#lua_isboolean">lua_isboolean</A><BR>
|
||||
<A HREF="manual.html#lua_iscfunction">lua_iscfunction</A><BR>
|
||||
<A HREF="manual.html#lua_isfunction">lua_isfunction</A><BR>
|
||||
<A HREF="manual.html#lua_islightuserdata">lua_islightuserdata</A><BR>
|
||||
<A HREF="manual.html#lua_isnil">lua_isnil</A><BR>
|
||||
<A HREF="manual.html#lua_isnumber">lua_isnumber</A><BR>
|
||||
<A HREF="manual.html#lua_isstring">lua_isstring</A><BR>
|
||||
<A HREF="manual.html#lua_istable">lua_istable</A><BR>
|
||||
<A HREF="manual.html#lua_isthread">lua_isthread</A><BR>
|
||||
<A HREF="manual.html#lua_isuserdata">lua_isuserdata</A><BR>
|
||||
<A HREF="manual.html#lua_lessthan">lua_lessthan</A><BR>
|
||||
<A HREF="manual.html#lua_load">lua_load</A><BR>
|
||||
<A HREF="manual.html#lua_newstate">lua_newstate</A><BR>
|
||||
<A HREF="manual.html#lua_newtable">lua_newtable</A><BR>
|
||||
<A HREF="manual.html#lua_newthread">lua_newthread</A><BR>
|
||||
<A HREF="manual.html#lua_newuserdata">lua_newuserdata</A><BR>
|
||||
<A HREF="manual.html#lua_next">lua_next</A><BR>
|
||||
<A HREF="manual.html#lua_objlen">lua_objlen</A><BR>
|
||||
<A HREF="manual.html#lua_pcall">lua_pcall</A><BR>
|
||||
<A HREF="manual.html#lua_pop">lua_pop</A><BR>
|
||||
<A HREF="manual.html#lua_pushboolean">lua_pushboolean</A><BR>
|
||||
<A HREF="manual.html#lua_pushcclosure">lua_pushcclosure</A><BR>
|
||||
<A HREF="manual.html#lua_pushcfunction">lua_pushcfunction</A><BR>
|
||||
<A HREF="manual.html#lua_pushfstring">lua_pushfstring</A><BR>
|
||||
<A HREF="manual.html#lua_pushinteger">lua_pushinteger</A><BR>
|
||||
<A HREF="manual.html#lua_pushlightuserdata">lua_pushlightuserdata</A><BR>
|
||||
<A HREF="manual.html#lua_pushlstring">lua_pushlstring</A><BR>
|
||||
<A HREF="manual.html#lua_pushnil">lua_pushnil</A><BR>
|
||||
<A HREF="manual.html#lua_pushnumber">lua_pushnumber</A><BR>
|
||||
<A HREF="manual.html#lua_pushstring">lua_pushstring</A><BR>
|
||||
<A HREF="manual.html#lua_pushthread">lua_pushthread</A><BR>
|
||||
<A HREF="manual.html#lua_pushvalue">lua_pushvalue</A><BR>
|
||||
<A HREF="manual.html#lua_pushvfstring">lua_pushvfstring</A><BR>
|
||||
<A HREF="manual.html#lua_rawequal">lua_rawequal</A><BR>
|
||||
<A HREF="manual.html#lua_rawget">lua_rawget</A><BR>
|
||||
<A HREF="manual.html#lua_rawgeti">lua_rawgeti</A><BR>
|
||||
<A HREF="manual.html#lua_rawset">lua_rawset</A><BR>
|
||||
<A HREF="manual.html#lua_rawseti">lua_rawseti</A><BR>
|
||||
<A HREF="manual.html#lua_register">lua_register</A><BR>
|
||||
<A HREF="manual.html#lua_remove">lua_remove</A><BR>
|
||||
<A HREF="manual.html#lua_replace">lua_replace</A><BR>
|
||||
<A HREF="manual.html#lua_resume">lua_resume</A><BR>
|
||||
<A HREF="manual.html#lua_setallocf">lua_setallocf</A><BR>
|
||||
<A HREF="manual.html#lua_setfenv">lua_setfenv</A><BR>
|
||||
<A HREF="manual.html#lua_setfield">lua_setfield</A><BR>
|
||||
<A HREF="manual.html#lua_setglobal">lua_setglobal</A><BR>
|
||||
<A HREF="manual.html#lua_sethook">lua_sethook</A><BR>
|
||||
<A HREF="manual.html#lua_setlocal">lua_setlocal</A><BR>
|
||||
<A HREF="manual.html#lua_setmetatable">lua_setmetatable</A><BR>
|
||||
<A HREF="manual.html#lua_settable">lua_settable</A><BR>
|
||||
<A HREF="manual.html#lua_settop">lua_settop</A><BR>
|
||||
<A HREF="manual.html#lua_setupvalue">lua_setupvalue</A><BR>
|
||||
<A HREF="manual.html#lua_status">lua_status</A><BR>
|
||||
<A HREF="manual.html#lua_toboolean">lua_toboolean</A><BR>
|
||||
<A HREF="manual.html#lua_tocfunction">lua_tocfunction</A><BR>
|
||||
<A HREF="manual.html#lua_tointeger">lua_tointeger</A><BR>
|
||||
<A HREF="manual.html#lua_tolstring">lua_tolstring</A><BR>
|
||||
<A HREF="manual.html#lua_tonumber">lua_tonumber</A><BR>
|
||||
<A HREF="manual.html#lua_topointer">lua_topointer</A><BR>
|
||||
<A HREF="manual.html#lua_tostring">lua_tostring</A><BR>
|
||||
<A HREF="manual.html#lua_tothread">lua_tothread</A><BR>
|
||||
<A HREF="manual.html#lua_touserdata">lua_touserdata</A><BR>
|
||||
<A HREF="manual.html#lua_type">lua_type</A><BR>
|
||||
<A HREF="manual.html#lua_typename">lua_typename</A><BR>
|
||||
<A HREF="manual.html#lua_xmove">lua_xmove</A><BR>
|
||||
<A HREF="manual.html#lua_yield">lua_yield</A><BR>
|
||||
|
||||
</TD>
|
||||
<TD>
|
||||
<H3>Auxiliary library</H3>
|
||||
<A HREF="manual.html#luaL_Buffer">luaL_Buffer</A><BR>
|
||||
<A HREF="manual.html#luaL_Reg">luaL_Reg</A><BR>
|
||||
<A HREF="manual.html#luaL_addchar">luaL_addchar</A><BR>
|
||||
<A HREF="manual.html#luaL_addlstring">luaL_addlstring</A><BR>
|
||||
<A HREF="manual.html#luaL_addsize">luaL_addsize</A><BR>
|
||||
<A HREF="manual.html#luaL_addstring">luaL_addstring</A><BR>
|
||||
<A HREF="manual.html#luaL_addvalue">luaL_addvalue</A><BR>
|
||||
<A HREF="manual.html#luaL_argcheck">luaL_argcheck</A><BR>
|
||||
<A HREF="manual.html#luaL_argerror">luaL_argerror</A><BR>
|
||||
<A HREF="manual.html#luaL_buffinit">luaL_buffinit</A><BR>
|
||||
<A HREF="manual.html#luaL_callmeta">luaL_callmeta</A><BR>
|
||||
<A HREF="manual.html#luaL_checkany">luaL_checkany</A><BR>
|
||||
<A HREF="manual.html#luaL_checkint">luaL_checkint</A><BR>
|
||||
<A HREF="manual.html#luaL_checkinteger">luaL_checkinteger</A><BR>
|
||||
<A HREF="manual.html#luaL_checklong">luaL_checklong</A><BR>
|
||||
<A HREF="manual.html#luaL_checklstring">luaL_checklstring</A><BR>
|
||||
<A HREF="manual.html#luaL_checknumber">luaL_checknumber</A><BR>
|
||||
<A HREF="manual.html#luaL_checkoption">luaL_checkoption</A><BR>
|
||||
<A HREF="manual.html#luaL_checkstack">luaL_checkstack</A><BR>
|
||||
<A HREF="manual.html#luaL_checkstring">luaL_checkstring</A><BR>
|
||||
<A HREF="manual.html#luaL_checktype">luaL_checktype</A><BR>
|
||||
<A HREF="manual.html#luaL_checkudata">luaL_checkudata</A><BR>
|
||||
<A HREF="manual.html#luaL_error">luaL_error</A><BR>
|
||||
<A HREF="manual.html#luaL_getmetafield">luaL_getmetafield</A><BR>
|
||||
<A HREF="manual.html#luaL_getmetatable">luaL_getmetatable</A><BR>
|
||||
<A HREF="manual.html#luaL_gsub">luaL_gsub</A><BR>
|
||||
<A HREF="manual.html#luaL_loadbuffer">luaL_loadbuffer</A><BR>
|
||||
<A HREF="manual.html#luaL_loadfile">luaL_loadfile</A><BR>
|
||||
<A HREF="manual.html#luaL_loadstring">luaL_loadstring</A><BR>
|
||||
<A HREF="manual.html#luaL_newmetatable">luaL_newmetatable</A><BR>
|
||||
<A HREF="manual.html#luaL_newstate">luaL_newstate</A><BR>
|
||||
<A HREF="manual.html#luaL_openlibs">luaL_openlibs</A><BR>
|
||||
<A HREF="manual.html#luaL_optint">luaL_optint</A><BR>
|
||||
<A HREF="manual.html#luaL_optinteger">luaL_optinteger</A><BR>
|
||||
<A HREF="manual.html#luaL_optlong">luaL_optlong</A><BR>
|
||||
<A HREF="manual.html#luaL_optlstring">luaL_optlstring</A><BR>
|
||||
<A HREF="manual.html#luaL_optnumber">luaL_optnumber</A><BR>
|
||||
<A HREF="manual.html#luaL_optstring">luaL_optstring</A><BR>
|
||||
<A HREF="manual.html#luaL_prepbuffer">luaL_prepbuffer</A><BR>
|
||||
<A HREF="manual.html#luaL_pushresult">luaL_pushresult</A><BR>
|
||||
<A HREF="manual.html#luaL_ref">luaL_ref</A><BR>
|
||||
<A HREF="manual.html#luaL_register">luaL_register</A><BR>
|
||||
<A HREF="manual.html#luaL_typename">luaL_typename</A><BR>
|
||||
<A HREF="manual.html#luaL_typerror">luaL_typerror</A><BR>
|
||||
<A HREF="manual.html#luaL_unref">luaL_unref</A><BR>
|
||||
<A HREF="manual.html#luaL_where">luaL_where</A><BR>
|
||||
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<P>
|
||||
|
||||
<HR>
|
||||
<SMALL>
|
||||
Last update:
|
||||
Fri Feb 10 17:15:37 BRST 2006
|
||||
</SMALL>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
BIN
doc/lua/logo.gif
Normal file
BIN
doc/lua/logo.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.1 KiB |
163
doc/lua/lua.1
Normal file
163
doc/lua/lua.1
Normal file
@ -0,0 +1,163 @@
|
||||
.\" $Id: lua.man,v 1.11 2006/01/06 16:03:34 lhf Exp $
|
||||
.TH LUA 1 "$Date: 2006/01/06 16:03:34 $"
|
||||
.SH NAME
|
||||
lua \- Lua interpreter
|
||||
.SH SYNOPSIS
|
||||
.B lua
|
||||
[
|
||||
.I options
|
||||
]
|
||||
[
|
||||
.I script
|
||||
[
|
||||
.I args
|
||||
]
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.B lua
|
||||
is the stand-alone Lua interpreter.
|
||||
It loads and executes Lua programs,
|
||||
either in textual source form or
|
||||
in precompiled binary form.
|
||||
(Precompiled binaries are output by
|
||||
.BR luac ,
|
||||
the Lua compiler.)
|
||||
.B lua
|
||||
can be used as a batch interpreter and also interactively.
|
||||
.LP
|
||||
The given
|
||||
.I options
|
||||
(see below)
|
||||
are executed and then
|
||||
the Lua program in file
|
||||
.I script
|
||||
is loaded and executed.
|
||||
The given
|
||||
.I args
|
||||
are available to
|
||||
.I script
|
||||
as strings in a global table named
|
||||
.BR arg .
|
||||
If these arguments contain spaces or other characters special to the shell,
|
||||
then they should be quoted
|
||||
(but note that the quotes will be removed by the shell).
|
||||
The arguments in
|
||||
.B arg
|
||||
start at 0,
|
||||
which contains the string
|
||||
.RI ' script '.
|
||||
The index of the last argument is stored in
|
||||
.BR arg.n .
|
||||
The arguments given in the command line before
|
||||
.IR script ,
|
||||
including the name of the interpreter,
|
||||
are available in negative indices in
|
||||
.BR arg .
|
||||
.LP
|
||||
At the very start,
|
||||
before even handling the command line,
|
||||
.B lua
|
||||
executes the contents of the environment variable
|
||||
.BR LUA_INIT ,
|
||||
if it is defined.
|
||||
If the value of
|
||||
.B LUA_INIT
|
||||
is of the form
|
||||
.RI '@ filename ',
|
||||
then
|
||||
.I filename
|
||||
is executed.
|
||||
Otherwise, the string is assumed to be a Lua statement and is executed.
|
||||
.LP
|
||||
Options start with
|
||||
.B '\-'
|
||||
and are described below.
|
||||
You can use
|
||||
.B "'\--'"
|
||||
to signal the end of options.
|
||||
.LP
|
||||
If no arguments are given,
|
||||
then
|
||||
.B "\-v \-i"
|
||||
is assumed when the standard input is a terminal;
|
||||
otherwise,
|
||||
.B "\-"
|
||||
is assumed.
|
||||
.LP
|
||||
In interactive mode,
|
||||
.B lua
|
||||
prompts the user,
|
||||
reads lines from the standard input,
|
||||
and executes them as they are read.
|
||||
If a line does not contain a complete statement,
|
||||
then a secondary prompt is displayed and
|
||||
lines are read until a complete statement is formed or
|
||||
a syntax error is found.
|
||||
So, one way to interrupt the reading of an incomplete statement is
|
||||
to force a syntax error:
|
||||
adding a
|
||||
.B ';'
|
||||
in the middle of a statement is a sure way of forcing a syntax error
|
||||
(except inside multiline strings and comments; these must be closed explicitly).
|
||||
If a line starts with
|
||||
.BR '=' ,
|
||||
then
|
||||
.B lua
|
||||
displays the values of all the expressions in the remainder of the
|
||||
line. The expressions must be separated by commas.
|
||||
The primary prompt is the value of the global variable
|
||||
.BR _PROMPT ,
|
||||
if this value is a string;
|
||||
otherwise, the default prompt is used.
|
||||
Similarly, the secondary prompt is the value of the global variable
|
||||
.BR _PROMPT2 .
|
||||
So,
|
||||
to change the prompts,
|
||||
set the corresponding variable to a string of your choice.
|
||||
You can do that after calling the interpreter
|
||||
or on the command line
|
||||
(but in this case you have to be careful with quotes
|
||||
if the prompt string contains a space; otherwise you may confuse the shell.)
|
||||
The default prompts are "> " and ">> ".
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-
|
||||
load and execute the standard input as a file,
|
||||
that is,
|
||||
not interactively,
|
||||
even when the standard input is a terminal.
|
||||
.TP
|
||||
.BI \-e " stat"
|
||||
execute statement
|
||||
.IR stat .
|
||||
You need to quote
|
||||
.I stat
|
||||
if it contains spaces, quotes,
|
||||
or other characters special to the shell.
|
||||
.TP
|
||||
.B \-i
|
||||
enter interactive mode after
|
||||
.I script
|
||||
is executed.
|
||||
.TP
|
||||
.BI \-l " name"
|
||||
call
|
||||
.BI require(' name ')
|
||||
before executing
|
||||
.IR script .
|
||||
Typically used to load libraries.
|
||||
.TP
|
||||
.B \-v
|
||||
show version information.
|
||||
.SH "SEE ALSO"
|
||||
.BR luac (1)
|
||||
.br
|
||||
http://www.lua.org/
|
||||
.SH DIAGNOSTICS
|
||||
Error messages should be self explanatory.
|
||||
.SH AUTHORS
|
||||
R. Ierusalimschy,
|
||||
L. H. de Figueiredo,
|
||||
and
|
||||
W. Celes
|
||||
.\" EOF
|
15
doc/lua/lua.css
Normal file
15
doc/lua/lua.css
Normal file
@ -0,0 +1,15 @@
|
||||
body {
|
||||
color: #000000 ;
|
||||
background-color: #FFFFFF ;
|
||||
font-family: sans-serif ;
|
||||
}
|
||||
|
||||
a:link {
|
||||
color: #000080 ;
|
||||
}
|
||||
|
||||
a:link:hover, a:visited:hover {
|
||||
color: #000080 ;
|
||||
background-color: #E0E0FF ;
|
||||
}
|
||||
|
172
doc/lua/lua.html
Normal file
172
doc/lua/lua.html
Normal file
@ -0,0 +1,172 @@
|
||||
<!-- $Id: lua.man,v 1.11 2006/01/06 16:03:34 lhf Exp $ -->
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>LUA man page</TITLE>
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
|
||||
</HEAD>
|
||||
|
||||
<BODY BGCOLOR="#FFFFFF">
|
||||
|
||||
<H2>NAME</H2>
|
||||
lua - Lua interpreter
|
||||
<H2>SYNOPSIS</H2>
|
||||
<B>lua</B>
|
||||
[
|
||||
<I>options</I>
|
||||
]
|
||||
[
|
||||
<I>script</I>
|
||||
[
|
||||
<I>args</I>
|
||||
]
|
||||
]
|
||||
<H2>DESCRIPTION</H2>
|
||||
<B>lua</B>
|
||||
is the stand-alone Lua interpreter.
|
||||
It loads and executes Lua programs,
|
||||
either in textual source form or
|
||||
in precompiled binary form.
|
||||
(Precompiled binaries are output by
|
||||
<B>luac</B>,
|
||||
the Lua compiler.)
|
||||
<B>lua</B>
|
||||
can be used as a batch interpreter and also interactively.
|
||||
<P>
|
||||
The given
|
||||
<I>options</I>
|
||||
(see below)
|
||||
are executed and then
|
||||
the Lua program in file
|
||||
<I>script</I>
|
||||
is loaded and executed.
|
||||
The given
|
||||
<I>args</I>
|
||||
are available to
|
||||
<I>script</I>
|
||||
as strings in a global table named
|
||||
<B>arg</B>.
|
||||
If these arguments contain spaces or other characters special to the shell,
|
||||
then they should be quoted
|
||||
(but note that the quotes will be removed by the shell).
|
||||
The arguments in
|
||||
<B>arg</B>
|
||||
start at 0,
|
||||
which contains the string
|
||||
'<I>script</I>'.
|
||||
The index of the last argument is stored in
|
||||
<B>arg.n</B>.
|
||||
The arguments given in the command line before
|
||||
<I>script</I>,
|
||||
including the name of the interpreter,
|
||||
are available in negative indices in
|
||||
<B>arg</B>.
|
||||
<P>
|
||||
At the very start,
|
||||
before even handling the command line,
|
||||
<B>lua</B>
|
||||
executes the contents of the environment variable
|
||||
<B>LUA_INIT</B>,
|
||||
if it is defined.
|
||||
If the value of
|
||||
<B>LUA_INIT</B>
|
||||
is of the form
|
||||
'@<I>filename</I>',
|
||||
then
|
||||
<I>filename</I>
|
||||
is executed.
|
||||
Otherwise, the string is assumed to be a Lua statement and is executed.
|
||||
<P>
|
||||
Options start with
|
||||
<B>'-'</B>
|
||||
and are described below.
|
||||
You can use
|
||||
<B>'--'</B>
|
||||
to signal the end of options.
|
||||
<P>
|
||||
If no arguments are given,
|
||||
then
|
||||
<B>"-v -i"</B>
|
||||
is assumed when the standard input is a terminal;
|
||||
otherwise,
|
||||
<B>"-"</B>
|
||||
is assumed.
|
||||
<P>
|
||||
In interactive mode,
|
||||
<B>lua</B>
|
||||
prompts the user,
|
||||
reads lines from the standard input,
|
||||
and executes them as they are read.
|
||||
If a line does not contain a complete statement,
|
||||
then a secondary prompt is displayed and
|
||||
lines are read until a complete statement is formed or
|
||||
a syntax error is found.
|
||||
So, one way to interrupt the reading of an incomplete statement is
|
||||
to force a syntax error:
|
||||
adding a
|
||||
<B>';'</B>
|
||||
in the middle of a statement is a sure way of forcing a syntax error
|
||||
(except inside multiline strings and comments; these must be closed explicitly).
|
||||
If a line starts with
|
||||
<B>'='</B>,
|
||||
then
|
||||
<B>lua</B>
|
||||
displays the values of all the expressions in the remainder of the
|
||||
line. The expressions must be separated by commas.
|
||||
The primary prompt is the value of the global variable
|
||||
<B>_PROMPT</B>,
|
||||
if this value is a string;
|
||||
otherwise, the default prompt is used.
|
||||
Similarly, the secondary prompt is the value of the global variable
|
||||
<B>_PROMPT2</B>.
|
||||
So,
|
||||
to change the prompts,
|
||||
set the corresponding variable to a string of your choice.
|
||||
You can do that after calling the interpreter
|
||||
or on the command line
|
||||
(but in this case you have to be careful with quotes
|
||||
if the prompt string contains a space; otherwise you may confuse the shell.)
|
||||
The default prompts are "> " and ">> ".
|
||||
<H2>OPTIONS</H2>
|
||||
<P>
|
||||
<B>-</B>
|
||||
load and execute the standard input as a file,
|
||||
that is,
|
||||
not interactively,
|
||||
even when the standard input is a terminal.
|
||||
<P>
|
||||
<B>-e </B><I>stat</I>
|
||||
execute statement
|
||||
<I>stat</I>.
|
||||
You need to quote
|
||||
<I>stat </I>
|
||||
if it contains spaces, quotes,
|
||||
or other characters special to the shell.
|
||||
<P>
|
||||
<B>-i</B>
|
||||
enter interactive mode after
|
||||
<I>script</I>
|
||||
is executed.
|
||||
<P>
|
||||
<B>-l </B><I>name</I>
|
||||
call
|
||||
<B>require</B>('<I>name</I>')
|
||||
before executing
|
||||
<I>script</I>.
|
||||
Typically used to load libraries.
|
||||
<P>
|
||||
<B>-v</B>
|
||||
show version information.
|
||||
<H2>SEE ALSO</H2>
|
||||
<B>luac</B>(1)
|
||||
<BR>
|
||||
<A HREF="http://www.lua.org/">http://www.lua.org/</A>
|
||||
<H2>DIAGNOSTICS</H2>
|
||||
Error messages should be self explanatory.
|
||||
<H2>AUTHORS</H2>
|
||||
R. Ierusalimschy,
|
||||
L. H. de Figueiredo,
|
||||
and
|
||||
W. Celes
|
||||
<!-- EOF -->
|
||||
</BODY>
|
||||
</HTML>
|
136
doc/lua/luac.1
Normal file
136
doc/lua/luac.1
Normal file
@ -0,0 +1,136 @@
|
||||
.\" $Id: luac.man,v 1.28 2006/01/06 16:03:34 lhf Exp $
|
||||
.TH LUAC 1 "$Date: 2006/01/06 16:03:34 $"
|
||||
.SH NAME
|
||||
luac \- Lua compiler
|
||||
.SH SYNOPSIS
|
||||
.B luac
|
||||
[
|
||||
.I options
|
||||
] [
|
||||
.I filenames
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.B luac
|
||||
is the Lua compiler.
|
||||
It translates programs written in the Lua programming language
|
||||
into binary files that can be later loaded and executed.
|
||||
.LP
|
||||
The main advantages of precompiling chunks are:
|
||||
faster loading,
|
||||
protecting source code from accidental user changes,
|
||||
and
|
||||
off-line syntax checking.
|
||||
.LP
|
||||
Pre-compiling does not imply faster execution
|
||||
because in Lua chunks are always compiled into bytecodes before being executed.
|
||||
.B luac
|
||||
simply allows those bytecodes to be saved in a file for later execution.
|
||||
.LP
|
||||
Pre-compiled chunks are not necessarily smaller than the corresponding source.
|
||||
The main goal in pre-compiling is faster loading.
|
||||
.LP
|
||||
The binary files created by
|
||||
.B luac
|
||||
are portable only among architectures with the same word size and byte order.
|
||||
.LP
|
||||
.B luac
|
||||
produces a single output file containing the bytecodes
|
||||
for all source files given.
|
||||
By default,
|
||||
the output file is named
|
||||
.BR luac.out ,
|
||||
but you can change this with the
|
||||
.B \-o
|
||||
option.
|
||||
.LP
|
||||
In the command line,
|
||||
you can mix
|
||||
text files containing Lua source and
|
||||
binary files containing precompiled chunks.
|
||||
This is useful to combine several precompiled chunks,
|
||||
even from different (but compatible) platforms,
|
||||
into a single precompiled chunk.
|
||||
.LP
|
||||
You can use
|
||||
.B "'\-'"
|
||||
to indicate the standard input as a source file
|
||||
and
|
||||
.B "'\--'"
|
||||
to signal the end of options
|
||||
(that is,
|
||||
all remaining arguments will be treated as files even if they start with
|
||||
.BR "'\-'" ).
|
||||
.LP
|
||||
The internal format of the binary files produced by
|
||||
.B luac
|
||||
is likely to change when a new version of Lua is released.
|
||||
So,
|
||||
save the source files of all Lua programs that you precompile.
|
||||
.LP
|
||||
.SH OPTIONS
|
||||
Options must be separate.
|
||||
.TP
|
||||
.B \-l
|
||||
produce a listing of the compiled bytecode for Lua's virtual machine.
|
||||
Listing bytecodes is useful to learn about Lua's virtual machine.
|
||||
If no files are given, then
|
||||
.B luac
|
||||
loads
|
||||
.B luac.out
|
||||
and lists its contents.
|
||||
.TP
|
||||
.BI \-o " file"
|
||||
output to
|
||||
.IR file ,
|
||||
instead of the default
|
||||
.BR luac.out .
|
||||
(You can use
|
||||
.B "'\-'"
|
||||
for standard output,
|
||||
but not on platforms that open standard output in text mode.)
|
||||
The output file may be a source file because
|
||||
all files are loaded before the output file is written.
|
||||
Be careful not to overwrite precious files.
|
||||
.TP
|
||||
.B \-p
|
||||
load files but do not generate any output file.
|
||||
Used mainly for syntax checking and for testing precompiled chunks:
|
||||
corrupted files will probably generate errors when loaded.
|
||||
Lua always performs a thorough integrity test on precompiled chunks.
|
||||
Bytecode that passes this test is completely safe,
|
||||
in the sense that it will not break the interpreter.
|
||||
However,
|
||||
there is no guarantee that such code does anything sensible.
|
||||
(None can be given, because the halting problem is unsolvable.)
|
||||
If no files are given, then
|
||||
.B luac
|
||||
loads
|
||||
.B luac.out
|
||||
and tests its contents.
|
||||
No messages are displayed if the file passes the integrity test.
|
||||
.TP
|
||||
.B \-s
|
||||
strip debug information before writing the output file.
|
||||
This saves some space in very large chunks,
|
||||
but if errors occur when running a stripped chunk,
|
||||
then the error messages may not contain the full information they usually do.
|
||||
For instance,
|
||||
line numbers and names of local variables are lost.
|
||||
.TP
|
||||
.B \-v
|
||||
show version information.
|
||||
.SH FILES
|
||||
.TP 15
|
||||
.B luac.out
|
||||
default output file
|
||||
.SH "SEE ALSO"
|
||||
.BR lua (1)
|
||||
.br
|
||||
http://www.lua.org/
|
||||
.SH DIAGNOSTICS
|
||||
Error messages should be self explanatory.
|
||||
.SH AUTHORS
|
||||
L. H. de Figueiredo,
|
||||
R. Ierusalimschy and
|
||||
W. Celes
|
||||
.\" EOF
|
145
doc/lua/luac.html
Normal file
145
doc/lua/luac.html
Normal file
@ -0,0 +1,145 @@
|
||||
<!-- $Id: luac.man,v 1.28 2006/01/06 16:03:34 lhf Exp $ -->
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>LUAC man page</TITLE>
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
|
||||
</HEAD>
|
||||
|
||||
<BODY BGCOLOR="#FFFFFF">
|
||||
|
||||
<H2>NAME</H2>
|
||||
luac - Lua compiler
|
||||
<H2>SYNOPSIS</H2>
|
||||
<B>luac</B>
|
||||
[
|
||||
<I>options</I>
|
||||
] [
|
||||
<I>filenames</I>
|
||||
]
|
||||
<H2>DESCRIPTION</H2>
|
||||
<B>luac</B>
|
||||
is the Lua compiler.
|
||||
It translates programs written in the Lua programming language
|
||||
into binary files that can be later loaded and executed.
|
||||
<P>
|
||||
The main advantages of precompiling chunks are:
|
||||
faster loading,
|
||||
protecting source code from accidental user changes,
|
||||
and
|
||||
off-line syntax checking.
|
||||
<P>
|
||||
Precompiling does not imply faster execution
|
||||
because in Lua chunks are always compiled into bytecodes before being executed.
|
||||
<B>luac</B>
|
||||
simply allows those bytecodes to be saved in a file for later execution.
|
||||
<P>
|
||||
Precompiled chunks are not necessarily smaller than the corresponding source.
|
||||
The main goal in precompiling is faster loading.
|
||||
<P>
|
||||
The binary files created by
|
||||
<B>luac</B>
|
||||
are portable only among architectures with the same word size and byte order.
|
||||
<P>
|
||||
<B>luac</B>
|
||||
produces a single output file containing the bytecodes
|
||||
for all source files given.
|
||||
By default,
|
||||
the output file is named
|
||||
<B>luac.out</B>,
|
||||
but you can change this with the
|
||||
<B>-o</B>
|
||||
option.
|
||||
<P>
|
||||
In the command line,
|
||||
you can mix
|
||||
text files containing Lua source and
|
||||
binary files containing precompiled chunks.
|
||||
This is useful because several precompiled chunks,
|
||||
even from different (but compatible) platforms,
|
||||
can be combined into a single precompiled chunk.
|
||||
<P>
|
||||
You can use
|
||||
<B>'-'</B>
|
||||
to indicate the standard input as a source file
|
||||
and
|
||||
<B>'--'</B>
|
||||
to signal the end of options
|
||||
(that is,
|
||||
all remaining arguments will be treated as files even if they start with
|
||||
<B>'-'</B>).
|
||||
<P>
|
||||
The internal format of the binary files produced by
|
||||
<B>luac</B>
|
||||
is likely to change when a new version of Lua is released.
|
||||
So,
|
||||
save the source files of all Lua programs that you precompile.
|
||||
<P>
|
||||
<H2>OPTIONS</H2>
|
||||
Options must be separate.
|
||||
<P>
|
||||
<B>-l</B>
|
||||
produce a listing of the compiled bytecode for Lua's virtual machine.
|
||||
Listing bytecodes is useful to learn about Lua's virtual machine.
|
||||
If no files are given, then
|
||||
<B>luac</B>
|
||||
loads
|
||||
<B>luac.out</B>
|
||||
and lists its contents.
|
||||
<P>
|
||||
<B>-o </B><I>file</I>
|
||||
output to
|
||||
<I>file</I>,
|
||||
instead of the default
|
||||
<B>luac.out</B>.
|
||||
(You can use
|
||||
<B>'-'</B>
|
||||
for standard output,
|
||||
but not on platforms that open standard output in text mode.)
|
||||
The output file may be a source file because
|
||||
all files are loaded before the output file is written.
|
||||
Be careful not to overwrite precious files.
|
||||
<P>
|
||||
<B>-p</B>
|
||||
load files but do not generate any output file.
|
||||
Used mainly for syntax checking and for testing precompiled chunks:
|
||||
corrupted files will probably generate errors when loaded.
|
||||
Lua always performs a thorough integrity test on precompiled chunks.
|
||||
Bytecode that passes this test is completely safe,
|
||||
in the sense that it will not break the interpreter.
|
||||
However,
|
||||
there is no guarantee that such code does anything sensible.
|
||||
(None can be given, because the halting problem is unsolvable.)
|
||||
If no files are given, then
|
||||
<B>luac</B>
|
||||
loads
|
||||
<B>luac.out</B>
|
||||
and tests its contents.
|
||||
No messages are displayed if the file passes the integrity test.
|
||||
<P>
|
||||
<B>-s</B>
|
||||
strip debug information before writing the output file.
|
||||
This saves some space in very large chunks,
|
||||
but if errors occur when running a stripped chunk,
|
||||
then the error messages may not contain the full information they usually do.
|
||||
For instance,
|
||||
line numbers and names of local variables are lost.
|
||||
<P>
|
||||
<B>-v</B>
|
||||
show version information.
|
||||
<H2>FILES</H2>
|
||||
<P>
|
||||
<B>luac.out</B>
|
||||
default output file
|
||||
<H2>SEE ALSO</H2>
|
||||
<B>lua</B>(1)
|
||||
<BR>
|
||||
<A HREF="http://www.lua.org/">http://www.lua.org/</A>
|
||||
<H2>DIAGNOSTICS</H2>
|
||||
Error messages should be self explanatory.
|
||||
<H2>AUTHORS</H2>
|
||||
L. H. de Figueiredo,
|
||||
R. Ierusalimschy and
|
||||
W. Celes
|
||||
<!-- EOF -->
|
||||
</BODY>
|
||||
</HTML>
|
6247
doc/lua/manual.html
Normal file
6247
doc/lua/manual.html
Normal file
File diff suppressed because it is too large
Load Diff
32
doc/lua/readme.html
Normal file
32
doc/lua/readme.html
Normal file
@ -0,0 +1,32 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Lua documentation</TITLE>
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
|
||||
</HEAD>
|
||||
|
||||
<BODY BGCOLOR="#FFFFFF">
|
||||
|
||||
<HR>
|
||||
<H1>
|
||||
<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua" BORDER=0></A>
|
||||
Documentation
|
||||
</H1>
|
||||
|
||||
<UL>
|
||||
<LI><A HREF="http://www.lua.org/">Official web site</A>
|
||||
<LI><A HREF="contents.html">Reference manual</A>
|
||||
<LI><A HREF="lua.html">lua man page</A>
|
||||
<LI><A HREF="luac.html">luac man page</A>
|
||||
<LI><A HREF="../README">lua/README</A>
|
||||
<LI><A HREF="../etc/README">lua/etc/README</A>
|
||||
<LI><A HREF="../test/README">lua/test/README</A>
|
||||
</UL>
|
||||
|
||||
<HR>
|
||||
<SMALL>
|
||||
Last update:
|
||||
Wed Sep 7 12:57:50 BRST 2005
|
||||
</SMALL>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
7
doc/luairc/LICENSE
Normal file
7
doc/luairc/LICENSE
Normal file
@ -0,0 +1,7 @@
|
||||
Copyright (c) 2007 Jesse Luehrs
|
||||
|
||||
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.
|
31
doc/luairc/README
Normal file
31
doc/luairc/README
Normal file
@ -0,0 +1,31 @@
|
||||
LuaIRC v0.3
|
||||
Jesse Luehrs (jluehrs2@uiuc.edu)
|
||||
|
||||
OVERVIEW
|
||||
========
|
||||
LuaIRC is a fully featured IRC framework written entirely in Lua. It provides an event driven system for connecting to IRC servers and responding to actions such as messages, joins/parts, and channel mode changes, among other things. DCC SEND is also fully implemented, both for sending and receiving files.
|
||||
|
||||
INSTALL
|
||||
=======
|
||||
This module requires LuaSocket (http://www.cs.princeton.edu/~diego/professional/luasocket/) and Lua 5.1. To install, modify the Make.config file with paths appropriate to your system and run 'make install'.
|
||||
|
||||
DOCUMENTATION
|
||||
=============
|
||||
Documentation of the API can be found in the doc/ directory. It was autogenerated from the source files by LuaDoc (http://luadoc.luaforge.net/).
|
||||
|
||||
LuaIRC has only been tested on Freenode so far, but I plan to expand this to other servers in the future. It's quite possible that it works on other servers anyway, however, so feel free to try it out, and send in bug reports for things that break.
|
||||
|
||||
CHANGES
|
||||
=======
|
||||
0.3
|
||||
- Major cleanup and restructuring again, documentation added, first public release
|
||||
0.2
|
||||
- Major cleanup and restructuring
|
||||
0.1
|
||||
- Initial implementation, enough to get it talking to the IRC server
|
||||
|
||||
COPYRIGHT AND LICENSE
|
||||
=====================
|
||||
Copyright (C) 2007 Jesse Luehrs
|
||||
|
||||
This code is distributed under the MIT license; a copy is in the LICENSE file distributed with the source.
|
20
doc/luairc/TODO
Normal file
20
doc/luairc/TODO
Normal file
@ -0,0 +1,20 @@
|
||||
- Reorganize the modules a bit more... we should have a src/irc/dcc/send.lua, src/irc/ctcp/base.lua, src/irc/ctcp/dcc.lua, etc. also, most (all?) of the handlers should be moved out of irc.lua into, say, src/irc/base.lua
|
||||
- Separate out the DCC module some more so that the callbacks aren't registered unless the module is loaded
|
||||
- Also separate out all of the CTCP commands/callbacks into the CTCP module
|
||||
- Rework the way irc.lua uses things from modules - the whole underscore but public thing... do i want to keep that? i suppose it's not horrible... look into this more
|
||||
- Implement callbacks for user mode changes (need to figure out how to represent users in the callback info)
|
||||
- Allow a server parameter in whois() so that the returned data can include the user's idle time
|
||||
- chan:ban()/chan:unban() should take a usermask, not a nick, or be able to generate a usermask from a nick, or something like that
|
||||
- Clean up misc.split
|
||||
- Implement DCC CHAT
|
||||
- Implement DCC XMIT/OFFER
|
||||
- Implement some more of the newer CTCP commands
|
||||
- Implement more information requests
|
||||
- who
|
||||
- whowas
|
||||
- info
|
||||
- stats
|
||||
- links
|
||||
- trace (not freenode supported)
|
||||
- Implement XDCC (?)
|
||||
- Handle endianness in the IP address conversion functions
|
156
doc/luairc/index.html
Normal file
156
doc/luairc/index.html
Normal file
@ -0,0 +1,156 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Reference</title>
|
||||
<link rel="stylesheet" href="luadoc.css" type="text/css" />
|
||||
<!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
<div id="main">
|
||||
|
||||
<div id="navigation">
|
||||
|
||||
|
||||
<h1>LuaDoc</h1>
|
||||
<ul>
|
||||
|
||||
<li><strong>Index</strong></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- Module list -->
|
||||
|
||||
<h1>Modules</h1>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<a href="modules/callbacks.html">callbacks</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="modules/irc.html">irc</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="modules/irc.channel.html">irc.channel</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="modules/irc.constants.html">irc.constants</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="modules/irc.ctcp.html">irc.ctcp</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="modules/irc.dcc.html">irc.dcc</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="modules/irc.debug.html">irc.debug</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="modules/irc.message.html">irc.message</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="modules/irc.misc.html">irc.misc</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<!-- File list -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div> <!-- id="navigation" -->
|
||||
|
||||
<div id="content">
|
||||
|
||||
|
||||
|
||||
<h2>Modules</h2>
|
||||
<table class="module_list">
|
||||
<!--<tr><td colspan="2">Modules</td></tr>-->
|
||||
|
||||
<tr>
|
||||
<td class="name"><a href="modules/callbacks.html">callbacks</a></td>
|
||||
<td class="summary">These are the callbacks that are available to register.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name"><a href="modules/irc.html">irc</a></td>
|
||||
<td class="summary">LuaIRC - IRC framework written in Lua </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name"><a href="modules/irc.channel.html">irc.channel</a></td>
|
||||
<td class="summary">This module implements a channel object representing a single channel we have joined.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name"><a href="modules/irc.constants.html">irc.constants</a></td>
|
||||
<td class="summary">This module holds various constants used by the IRC protocol.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name"><a href="modules/irc.ctcp.html">irc.ctcp</a></td>
|
||||
<td class="summary">This module implements the various quoting and escaping requirements of the CTCP protocol.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name"><a href="modules/irc.dcc.html">irc.dcc</a></td>
|
||||
<td class="summary">This module implements the DCC protocol.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name"><a href="modules/irc.debug.html">irc.debug</a></td>
|
||||
<td class="summary">This module implements a few useful debug functions for use throughout the rest of the code.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name"><a href="modules/irc.message.html">irc.message</a></td>
|
||||
<td class="summary">This module contains parsing functions for IRC server messages.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name"><a href="modules/irc.misc.html">irc.misc</a></td>
|
||||
<td class="summary">This module contains various useful functions which didn't fit in any of the other modules.</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
|
||||
</div> <!-- id="main" -->
|
||||
|
||||
<div id="about">
|
||||
<p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p>
|
||||
</div> <!-- id="about" -->
|
||||
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
286
doc/luairc/luadoc.css
Normal file
286
doc/luairc/luadoc.css
Normal file
@ -0,0 +1,286 @@
|
||||
body {
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
font-family: arial, helvetica, geneva, sans-serif;
|
||||
background-color:#ffffff; margin:0px;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: "Andale Mono", monospace;
|
||||
}
|
||||
|
||||
tt {
|
||||
font-family: "Andale Mono", monospace;
|
||||
}
|
||||
|
||||
body, td, th { font-size: 11pt; }
|
||||
|
||||
h1, h2, h3, h4 { margin-left: 0em; }
|
||||
|
||||
textarea, pre, tt { font-size:10pt; }
|
||||
body, td, th { color:#000000; }
|
||||
small { font-size:0.85em; }
|
||||
h1 { font-size:1.5em; }
|
||||
h2 { font-size:1.25em; }
|
||||
h3 { font-size:1.15em; }
|
||||
h4 { font-size:1.06em; }
|
||||
|
||||
a:link { font-weight:bold; color: #004080; text-decoration: none; }
|
||||
a:visited { font-weight:bold; color: #006699; text-decoration: none; }
|
||||
a:link:hover { text-decoration:underline; }
|
||||
hr { color:#cccccc }
|
||||
img { border-width: 0px; }
|
||||
|
||||
|
||||
h3 { padding-top: 1em; }
|
||||
|
||||
p { margin-left: 1em; }
|
||||
|
||||
p.name {
|
||||
font-family: "Andale Mono", monospace;
|
||||
padding-top: 1em;
|
||||
margin-left: 0em;
|
||||
}
|
||||
|
||||
blockquote { margin-left: 3em; }
|
||||
|
||||
pre.example {
|
||||
background-color: rgb(245, 245, 245);
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-style: solid;
|
||||
border-right-style: solid;
|
||||
border-bottom-style: solid;
|
||||
border-left-style: solid;
|
||||
border-top-color: silver;
|
||||
border-right-color: silver;
|
||||
border-bottom-color: silver;
|
||||
border-left-color: silver;
|
||||
padding: 1em;
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
font-family: "Andale Mono", monospace;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
|
||||
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; }
|
||||
|
||||
table {
|
||||
border: 1px solid black;
|
||||
border-collapse: collapse;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
th {
|
||||
border: 1px solid black;
|
||||
padding: 0.5em;
|
||||
}
|
||||
td {
|
||||
border: 1px solid black;
|
||||
padding: 0.5em;
|
||||
}
|
||||
div.header, div.footer { margin-left: 0em; }
|
||||
|
||||
#container
|
||||
{
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
#product
|
||||
{
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
#product big {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
#product_logo
|
||||
{
|
||||
}
|
||||
|
||||
#product_name
|
||||
{
|
||||
}
|
||||
|
||||
#product_description
|
||||
{
|
||||
}
|
||||
|
||||
#main
|
||||
{
|
||||
background-color: #f0f0f0;
|
||||
border-left: 2px solid #cccccc;
|
||||
}
|
||||
|
||||
#navigation
|
||||
{
|
||||
float: left;
|
||||
width: 18em;
|
||||
margin: 0;
|
||||
vertical-align: top;
|
||||
background-color: #f0f0f0;
|
||||
overflow:visible;
|
||||
}
|
||||
|
||||
#navigation h1 {
|
||||
background-color:#e7e7e7;
|
||||
font-size:1.1em;
|
||||
color:#000000;
|
||||
text-align:left;
|
||||
margin:0px;
|
||||
padding:0.2em;
|
||||
border-top:1px solid #dddddd;
|
||||
border-bottom:1px solid #dddddd;
|
||||
}
|
||||
|
||||
#navigation ul
|
||||
{
|
||||
font-size:1em;
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 1px;
|
||||
}
|
||||
|
||||
#navigation li
|
||||
{
|
||||
text-indent: -1em;
|
||||
margin: 0em 0em 0em 0.5em;
|
||||
display: block;
|
||||
padding: 3px 0px 0px 12px;
|
||||
}
|
||||
|
||||
#navigation li li a
|
||||
{
|
||||
padding: 0px 3px 0px -1em;
|
||||
}
|
||||
|
||||
#content
|
||||
{
|
||||
margin-left: 18em;
|
||||
padding: 1em;
|
||||
border-left: 2px solid #cccccc;
|
||||
border-right: 2px solid #cccccc;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
#about
|
||||
{
|
||||
clear: both;
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
border-top: 2px solid #cccccc;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
@media print {
|
||||
body {
|
||||
font: 12pt "Times New Roman", "TimeNR", Times, serif;
|
||||
}
|
||||
a { font-weight:bold; color: #004080; text-decoration: underline; }
|
||||
|
||||
#main
{
background-color: #ffffff;
border-left: 0px;
}
|
||||
#container
{
margin-left: 2%;
margin-right: 2%;
background-color: #ffffff;
}
|
||||
|
||||
#content
{
margin-left: 0px;
padding: 1em;
border-left: 0px;
border-right: 0px;
background-color: #ffffff;
}
|
||||
|
||||
#navigation
{
display: none;
|
||||
}
|
||||
pre.example {
|
||||
font-family: "Andale Mono", monospace;
|
||||
font-size: 10pt;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
}
|
||||
|
||||
table.module_list td
|
||||
{
|
||||
border-width: 1px;
|
||||
padding: 3px;
|
||||
border-style: solid;
|
||||
border-color: #cccccc;
|
||||
}
|
||||
table.module_list td.name { background-color: #f0f0f0; }
|
||||
table.module_list td.summary { width: 100%; }
|
||||
|
||||
table.file_list
|
||||
{
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #cccccc;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.file_list td
|
||||
{
|
||||
border-width: 1px;
|
||||
padding: 3px;
|
||||
border-style: solid;
|
||||
border-color: #cccccc;
|
||||
}
|
||||
table.file_list td.name { background-color: #f0f0f0; }
|
||||
table.file_list td.summary { width: 100%; }
|
||||
|
||||
|
||||
table.function_list
|
||||
{
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #cccccc;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.function_list td
|
||||
{
|
||||
border-width: 1px;
|
||||
padding: 3px;
|
||||
border-style: solid;
|
||||
border-color: #cccccc;
|
||||
}
|
||||
table.function_list td.name { background-color: #f0f0f0; }
|
||||
table.function_list td.summary { width: 100%; }
|
||||
|
||||
|
||||
table.table_list
|
||||
{
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #cccccc;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.table_list td
|
||||
{
|
||||
border-width: 1px;
|
||||
padding: 3px;
|
||||
border-style: solid;
|
||||
border-color: #cccccc;
|
||||
}
|
||||
table.table_list td.name { background-color: #f0f0f0; }
|
||||
table.table_list td.summary { width: 100%; }
|
||||
|
||||
dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;}
|
||||
dl.function dd {padding-bottom: 1em;}
|
||||
dl.function h3 {padding: 0; margin: 0; font-size: medium;}
|
||||
|
||||
dl.table dt {border-top: 1px solid #ccc; padding-top: 1em;}
|
||||
dl.table dd {padding-bottom: 1em;}
|
||||
dl.table h3 {padding: 0; margin: 0; font-size: medium;}
|
||||
|
||||
#TODO: make module_list, file_list, function_list, table_list inherit from a list
|
||||
|
858
doc/luairc/modules/callbacks.html
Normal file
858
doc/luairc/modules/callbacks.html
Normal file
@ -0,0 +1,858 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Reference</title>
|
||||
<link rel="stylesheet" href="../luadoc.css" type="text/css" />
|
||||
<!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
<div id="main">
|
||||
|
||||
<div id="navigation">
|
||||
|
||||
|
||||
<h1>LuaDoc</h1>
|
||||
<ul>
|
||||
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- Module list -->
|
||||
|
||||
<h1>Modules</h1>
|
||||
<ul>
|
||||
|
||||
<li><strong>callbacks</strong></li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.html">irc</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.channel.html">irc.channel</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.constants.html">irc.constants</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.ctcp.html">irc.ctcp</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.dcc.html">irc.dcc</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.debug.html">irc.debug</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.message.html">irc.message</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.misc.html">irc.misc</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<!-- File list -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div><!-- id="navigation" -->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Module <code>callbacks</code></h1>
|
||||
|
||||
<p>These are the callbacks that are available to register.</p>
|
||||
|
||||
|
||||
|
||||
<h2>Functions</h2>
|
||||
<table class="function_list">
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#channel_act">channel_act</a> (channel, from, message)</td>
|
||||
<td class="summary">This callback is triggered whenever a user performs a CTCP ACTION in a channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#channel_msg">channel_msg</a> (channel, from, message)</td>
|
||||
<td class="summary">This callback is triggered whenever a user sends a message to a channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#channel_notice">channel_notice</a> (channel, from, message)</td>
|
||||
<td class="summary">This callback is triggered whenever a user sends a notice to a channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#connect">connect</a> ()</td>
|
||||
<td class="summary">This callback is triggered when the connection has completed.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#ctcp_error">ctcp_error</a> (from, to, message)</td>
|
||||
<td class="summary">This callback is triggered when a CTCP command resulted in an error (for example, if the remote client doesn't implement that CTCP command).</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#dcc_send">dcc_send</a> (from, to, filename, address, port, filesize)</td>
|
||||
<td class="summary">This callback is triggered when a user offers to send you a file using DCC SEND.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#deop">deop</a> (channel, from, to)</td>
|
||||
<td class="summary">This callback is triggered whenever somebody loses ops.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#devoice">devoice</a> (channel, from, to)</td>
|
||||
<td class="summary">This callback is triggered whenever somebody loses voice.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#invite">invite</a> (from, channel)</td>
|
||||
<td class="summary">This callback is triggered whenever an invite to a channel is received.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#join">join</a> (channel, from)</td>
|
||||
<td class="summary">This callback is triggered when a user joins a channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#kick">kick</a> (channel, to, from)</td>
|
||||
<td class="summary">This callback is triggered when a user is kicked from a channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#me_join">me_join</a> (channel)</td>
|
||||
<td class="summary">This callback is triggered after a join() command completes.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#nick_change">nick_change</a> (from, old_nick)</td>
|
||||
<td class="summary">This callback is triggered when a user changes their nick.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#op">op</a> (channel, from, to)</td>
|
||||
<td class="summary">This callback is triggered when a user is opped.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#part">part</a> (channel, from, message)</td>
|
||||
<td class="summary">This callback is triggered when a user leaves a channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#private_act">private_act</a> (from, message)</td>
|
||||
<td class="summary">This callback is triggered when a user sends a CTCP ACTION in a private message.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#private_msg">private_msg</a> (from, message)</td>
|
||||
<td class="summary">This callback is triggered when a user sends a private message.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#private_notice">private_notice</a> (from, message)</td>
|
||||
<td class="summary">This callback is triggered when a user sends a private notice.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#quit">quit</a> (from, message)</td>
|
||||
<td class="summary">This callback is triggered when a user quits.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#topic_change">topic_change</a> (channel)</td>
|
||||
<td class="summary">This callback is triggered when a user changes the topic in a channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#voice">voice</a> (channel, from, to)</td>
|
||||
<td class="summary">This callback is triggered when a user is voiced.</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
<h2><a name="functions"></a>Functions</h2>
|
||||
<dl class="function">
|
||||
|
||||
|
||||
|
||||
<dt><a name="channel_act"></a><strong>channel_act</strong> (channel, from, message)</dt>
|
||||
<dd>
|
||||
This callback is triggered whenever a user performs a CTCP ACTION in a channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
channel: Channel object for where the action was performed
|
||||
</li>
|
||||
|
||||
<li>
|
||||
from: User who performed the action
|
||||
</li>
|
||||
|
||||
<li>
|
||||
message: The action which was performed
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="channel_msg"></a><strong>channel_msg</strong> (channel, from, message)</dt>
|
||||
<dd>
|
||||
This callback is triggered whenever a user sends a message to a channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
channel: Channel object for where the message was sent
|
||||
</li>
|
||||
|
||||
<li>
|
||||
from: User who sent the message
|
||||
</li>
|
||||
|
||||
<li>
|
||||
message: The message which was sent
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="channel_notice"></a><strong>channel_notice</strong> (channel, from, message)</dt>
|
||||
<dd>
|
||||
This callback is triggered whenever a user sends a notice to a channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
channel: Channel object for where the notice was sent
|
||||
</li>
|
||||
|
||||
<li>
|
||||
from: User who sent the message
|
||||
</li>
|
||||
|
||||
<li>
|
||||
message: The notice which was sent
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="connect"></a><strong>connect</strong> ()</dt>
|
||||
<dd>
|
||||
This callback is triggered when the connection has completed.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="ctcp_error"></a><strong>ctcp_error</strong> (from, to, message)</dt>
|
||||
<dd>
|
||||
This callback is triggered when a CTCP command resulted in an error (for example, if the remote client doesn't implement that CTCP command).
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
from: User who sent the error response
|
||||
</li>
|
||||
|
||||
<li>
|
||||
to: Who the response was sent to (either you or a channel you are in)
|
||||
</li>
|
||||
|
||||
<li>
|
||||
message: A description of the error
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="dcc_send"></a><strong>dcc_send</strong> (from, to, filename, address, port, filesize)</dt>
|
||||
<dd>
|
||||
This callback is triggered when a user offers to send you a file using DCC SEND. It allows you to determine whether or not you want to accept the file.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
from: User offering the file
|
||||
</li>
|
||||
|
||||
<li>
|
||||
to: User who is being offered the file (likely yourself)
|
||||
</li>
|
||||
|
||||
<li>
|
||||
filename: Name of the file being offered
|
||||
</li>
|
||||
|
||||
<li>
|
||||
address: IP address of the user offering the file
|
||||
</li>
|
||||
|
||||
<li>
|
||||
port: Port to connect to at that address
|
||||
</li>
|
||||
|
||||
<li>
|
||||
filesize: Size of the file being offered
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Return value:</h3>
|
||||
True to accept the file, false to reject it
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="deop"></a><strong>deop</strong> (channel, from, to)</dt>
|
||||
<dd>
|
||||
This callback is triggered whenever somebody loses ops.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
channel: Channel object for where the user lost ops
|
||||
</li>
|
||||
|
||||
<li>
|
||||
from: User who removed the ops
|
||||
</li>
|
||||
|
||||
<li>
|
||||
to: User who lost ops
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="devoice"></a><strong>devoice</strong> (channel, from, to)</dt>
|
||||
<dd>
|
||||
This callback is triggered whenever somebody loses voice.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
channel: Channel object for where the user lost voice
|
||||
</li>
|
||||
|
||||
<li>
|
||||
from: User who removed the voice
|
||||
</li>
|
||||
|
||||
<li>
|
||||
to: User who lost voice
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="invite"></a><strong>invite</strong> (from, channel)</dt>
|
||||
<dd>
|
||||
This callback is triggered whenever an invite to a channel is received.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
from: User who sent the invite
|
||||
</li>
|
||||
|
||||
<li>
|
||||
channel: Channel name that the invite was to
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="join"></a><strong>join</strong> (channel, from)</dt>
|
||||
<dd>
|
||||
This callback is triggered when a user joins a channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
channel: Channel object for where there was a join
|
||||
</li>
|
||||
|
||||
<li>
|
||||
from: User who joined
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="kick"></a><strong>kick</strong> (channel, to, from)</dt>
|
||||
<dd>
|
||||
This callback is triggered when a user is kicked from a channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
channel: Channel object for where there was a kick
|
||||
</li>
|
||||
|
||||
<li>
|
||||
to: User who was kicked
|
||||
</li>
|
||||
|
||||
<li>
|
||||
from: User who did the kicking
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="me_join"></a><strong>me_join</strong> (channel)</dt>
|
||||
<dd>
|
||||
This callback is triggered after a join() command completes.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
channel: Channel object for the joined channel
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="nick_change"></a><strong>nick_change</strong> (from, old_nick)</dt>
|
||||
<dd>
|
||||
This callback is triggered when a user changes their nick.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
from: User who changed their nick
|
||||
</li>
|
||||
|
||||
<li>
|
||||
old_nick: The previous nick of that user
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="op"></a><strong>op</strong> (channel, from, to)</dt>
|
||||
<dd>
|
||||
This callback is triggered when a user is opped.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
channel: Channel object for where the user was opped
|
||||
</li>
|
||||
|
||||
<li>
|
||||
from: User who gave the ops
|
||||
</li>
|
||||
|
||||
<li>
|
||||
to: User who was opped
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="part"></a><strong>part</strong> (channel, from, message)</dt>
|
||||
<dd>
|
||||
This callback is triggered when a user leaves a channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
channel: Channel object for where the part occurred
|
||||
</li>
|
||||
|
||||
<li>
|
||||
from: User who left
|
||||
</li>
|
||||
|
||||
<li>
|
||||
message: Part message from the user
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="private_act"></a><strong>private_act</strong> (from, message)</dt>
|
||||
<dd>
|
||||
This callback is triggered when a user sends a CTCP ACTION in a private message.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
from: User who sent the action
|
||||
</li>
|
||||
|
||||
<li>
|
||||
message: The action that was sent
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="private_msg"></a><strong>private_msg</strong> (from, message)</dt>
|
||||
<dd>
|
||||
This callback is triggered when a user sends a private message.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
from: User who sent the message
|
||||
</li>
|
||||
|
||||
<li>
|
||||
message: The message that was sent
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="private_notice"></a><strong>private_notice</strong> (from, message)</dt>
|
||||
<dd>
|
||||
This callback is triggered when a user sends a private notice.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
from: User who sent the notice
|
||||
</li>
|
||||
|
||||
<li>
|
||||
message: The notice that was sent
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="quit"></a><strong>quit</strong> (from, message)</dt>
|
||||
<dd>
|
||||
This callback is triggered when a user quits.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
from: User who quit
|
||||
</li>
|
||||
|
||||
<li>
|
||||
message: The user's quit message
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="topic_change"></a><strong>topic_change</strong> (channel)</dt>
|
||||
<dd>
|
||||
This callback is triggered when a user changes the topic in a channel. The contents of the topic can be seen in the <i>topic</i> field of the channel object.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
channel: Channel object for where the topic was changed.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="voice"></a><strong>voice</strong> (channel, from, to)</dt>
|
||||
<dd>
|
||||
This callback is triggered when a user is voiced.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
channel: Channel object for where the user was voiced
|
||||
</li>
|
||||
|
||||
<li>
|
||||
from: User who gave the voice
|
||||
</li>
|
||||
|
||||
<li>
|
||||
to: User who was voiced
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
|
||||
</div> <!-- id="main" -->
|
||||
|
||||
<div id="about">
|
||||
<p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p>
|
||||
</div> <!-- id="about" -->
|
||||
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
945
doc/luairc/modules/irc.channel.html
Normal file
945
doc/luairc/modules/irc.channel.html
Normal file
@ -0,0 +1,945 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Reference</title>
|
||||
<link rel="stylesheet" href="../luadoc.css" type="text/css" />
|
||||
<!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
<div id="main">
|
||||
|
||||
<div id="navigation">
|
||||
|
||||
|
||||
<h1>LuaDoc</h1>
|
||||
<ul>
|
||||
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- Module list -->
|
||||
|
||||
<h1>Modules</h1>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<a href="../modules/callbacks.html">callbacks</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.html">irc</a>
|
||||
</li>
|
||||
|
||||
<li><strong>irc.channel</strong></li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.constants.html">irc.constants</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.ctcp.html">irc.ctcp</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.dcc.html">irc.dcc</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.debug.html">irc.debug</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.message.html">irc.message</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.misc.html">irc.misc</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<!-- File list -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div><!-- id="navigation" -->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Module <code>irc.channel</code></h1>
|
||||
|
||||
<p>This module implements a channel object representing a single channel we have joined.</p>
|
||||
|
||||
|
||||
|
||||
<h2>Functions</h2>
|
||||
<table class="function_list">
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#ban">ban</a> (self, name)</td>
|
||||
<td class="summary">Ban a user from a channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#contains">contains</a> (self, nick)</td>
|
||||
<td class="summary">Test if a user is in the channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#deop">deop</a> (self, name)</td>
|
||||
<td class="summary">Remove ops from a user.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#devoice">devoice</a> (self, name)</td>
|
||||
<td class="summary">Remove voice from a user.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#each_member">each_member</a> (self)</td>
|
||||
<td class="summary">Iterator over all users in the channel </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#each_op">each_op</a> (self)</td>
|
||||
<td class="summary">Iterator over the ops in the channel </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#each_user">each_user</a> (self)</td>
|
||||
<td class="summary">Iterator over the normal users in the channel </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#each_voice">each_voice</a> (self)</td>
|
||||
<td class="summary">Iterator over the voiced users in the channel </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#members">members</a> (self)</td>
|
||||
<td class="summary">Gets an array of all the users in the channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#new">new</a> (chan)</td>
|
||||
<td class="summary">Creates a new Channel object.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#op">op</a> (self, name)</td>
|
||||
<td class="summary">Give a user ops on a channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#ops">ops</a> (self)</td>
|
||||
<td class="summary">Gets an array of all the ops in the channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#set_invite_only">set_invite_only</a> (self, set)</td>
|
||||
<td class="summary">Set whether joining the channel requires an invite.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#set_key">set_key</a> (self, key)</td>
|
||||
<td class="summary">Set a channel password.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#set_limit">set_limit</a> (self, new_limit)</td>
|
||||
<td class="summary">Set a channel limit.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#set_moderated">set_moderated</a> (self, set)</td>
|
||||
<td class="summary">Set whether voice is required to speak.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#set_no_outside_messages">set_no_outside_messages</a> (self, set)</td>
|
||||
<td class="summary">If true, users must be in the channel to send messages to it.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#set_private">set_private</a> (self, set)</td>
|
||||
<td class="summary">Set the private state of a channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#set_secret">set_secret</a> (self, set)</td>
|
||||
<td class="summary">Set the secret state of a channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#set_topic_lock">set_topic_lock</a> (self, set)</td>
|
||||
<td class="summary">If true, the topic can only be changed by an op.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#unban">unban</a> (self, name)</td>
|
||||
<td class="summary">Remove a ban on a user.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#users">users</a> (self)</td>
|
||||
<td class="summary">Gets an array of all the normal users in the channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#voice">voice</a> (self, name)</td>
|
||||
<td class="summary">Give a user voice on a channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#voices">voices</a> (self)</td>
|
||||
<td class="summary">Gets an array of all the voiced users in the channel.</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>Tables</h2>
|
||||
<table class="table_list">
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#Channel">Channel</a></td>
|
||||
<td class="summary">An object of the Channel class represents a single joined channel.</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
<h2><a name="functions"></a>Functions</h2>
|
||||
<dl class="function">
|
||||
|
||||
|
||||
|
||||
<dt><a name="ban"></a><strong>ban</strong> (self, name)</dt>
|
||||
<dd>
|
||||
Ban a user from a channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
<li>
|
||||
name: User to ban
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="contains"></a><strong>contains</strong> (self, nick)</dt>
|
||||
<dd>
|
||||
Test if a user is in the channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
<li>
|
||||
nick: Nick to search for
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Return value:</h3>
|
||||
True if the nick is in the channel, false otherwise
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="deop"></a><strong>deop</strong> (self, name)</dt>
|
||||
<dd>
|
||||
Remove ops from a user.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
<li>
|
||||
name: User to remove ops from
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="devoice"></a><strong>devoice</strong> (self, name)</dt>
|
||||
<dd>
|
||||
Remove voice from a user.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
<li>
|
||||
name: User to remove voice from
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="each_member"></a><strong>each_member</strong> (self)</dt>
|
||||
<dd>
|
||||
Iterator over all users in the channel
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="each_op"></a><strong>each_op</strong> (self)</dt>
|
||||
<dd>
|
||||
Iterator over the ops in the channel
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="each_user"></a><strong>each_user</strong> (self)</dt>
|
||||
<dd>
|
||||
Iterator over the normal users in the channel
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="each_voice"></a><strong>each_voice</strong> (self)</dt>
|
||||
<dd>
|
||||
Iterator over the voiced users in the channel
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="members"></a><strong>members</strong> (self)</dt>
|
||||
<dd>
|
||||
Gets an array of all the users in the channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Return value:</h3>
|
||||
Array of channel users
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="new"></a><strong>new</strong> (chan)</dt>
|
||||
<dd>
|
||||
Creates a new Channel object.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
chan: Name of the new channel
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Return value:</h3>
|
||||
The new channel instance
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="op"></a><strong>op</strong> (self, name)</dt>
|
||||
<dd>
|
||||
Give a user ops on a channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
<li>
|
||||
name: User to op
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="ops"></a><strong>ops</strong> (self)</dt>
|
||||
<dd>
|
||||
Gets an array of all the ops in the channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Return value:</h3>
|
||||
Array of channel ops
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="set_invite_only"></a><strong>set_invite_only</strong> (self, set)</dt>
|
||||
<dd>
|
||||
Set whether joining the channel requires an invite.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
<li>
|
||||
set: True to set the channel invite only, false to unset it
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="set_key"></a><strong>set_key</strong> (self, key)</dt>
|
||||
<dd>
|
||||
Set a channel password.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
<li>
|
||||
key: New channel password (optional; password is unset if this argument isn't passed)
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="set_limit"></a><strong>set_limit</strong> (self, new_limit)</dt>
|
||||
<dd>
|
||||
Set a channel limit.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
<li>
|
||||
new_limit: New value for the channel limit (optional; limit is unset if this argument isn't passed)
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="set_moderated"></a><strong>set_moderated</strong> (self, set)</dt>
|
||||
<dd>
|
||||
Set whether voice is required to speak.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
<li>
|
||||
set: True to set the channel as moderated, false to unset it
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="set_no_outside_messages"></a><strong>set_no_outside_messages</strong> (self, set)</dt>
|
||||
<dd>
|
||||
If true, users must be in the channel to send messages to it.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
<li>
|
||||
set: True to require users to be in the channel to send messages to it, false to remove this restriction
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="set_private"></a><strong>set_private</strong> (self, set)</dt>
|
||||
<dd>
|
||||
Set the private state of a channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
<li>
|
||||
set: True to set the channel as private, false to unset it
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="set_secret"></a><strong>set_secret</strong> (self, set)</dt>
|
||||
<dd>
|
||||
Set the secret state of a channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
<li>
|
||||
set: True to set the channel as secret, false to unset it
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="set_topic_lock"></a><strong>set_topic_lock</strong> (self, set)</dt>
|
||||
<dd>
|
||||
If true, the topic can only be changed by an op.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
<li>
|
||||
set: True to lock the topic, false to unlock it
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="unban"></a><strong>unban</strong> (self, name)</dt>
|
||||
<dd>
|
||||
Remove a ban on a user.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
<li>
|
||||
name: User to unban
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="users"></a><strong>users</strong> (self)</dt>
|
||||
<dd>
|
||||
Gets an array of all the normal users in the channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Return value:</h3>
|
||||
Array of channel normal users
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="voice"></a><strong>voice</strong> (self, name)</dt>
|
||||
<dd>
|
||||
Give a user voice on a channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
<li>
|
||||
name: User to give voice to
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="voices"></a><strong>voices</strong> (self)</dt>
|
||||
<dd>
|
||||
Gets an array of all the voiced users in the channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
self: Channel object
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Return value:</h3>
|
||||
Array of channel voiced users
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
<h2><a name="tables"></a>Tables</h2>
|
||||
<dl class="table">
|
||||
|
||||
<dt><a name="Channel"></a><strong>Channel</strong></dt>
|
||||
<dd>An object of the Channel class represents a single joined channel. It has several table fields, and can be used in string contexts (returning the channel name).<br />
|
||||
|
||||
|
||||
<em>Fields</em>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
name: Name of the channel (read only)
|
||||
</li>
|
||||
|
||||
<li>
|
||||
topic: Channel topic, if set (read/write, writing to this sends a topic change request to the server for this channel)
|
||||
</li>
|
||||
|
||||
<li>
|
||||
chanmode: Channel mode (public/private/secret) (read only)
|
||||
</li>
|
||||
|
||||
<li>
|
||||
members: Array of all members of this channel
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
|
||||
</div> <!-- id="main" -->
|
||||
|
||||
<div id="about">
|
||||
<p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p>
|
||||
</div> <!-- id="about" -->
|
||||
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
117
doc/luairc/modules/irc.constants.html
Normal file
117
doc/luairc/modules/irc.constants.html
Normal file
@ -0,0 +1,117 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Reference</title>
|
||||
<link rel="stylesheet" href="../luadoc.css" type="text/css" />
|
||||
<!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
<div id="main">
|
||||
|
||||
<div id="navigation">
|
||||
|
||||
|
||||
<h1>LuaDoc</h1>
|
||||
<ul>
|
||||
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- Module list -->
|
||||
|
||||
<h1>Modules</h1>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<a href="../modules/callbacks.html">callbacks</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.html">irc</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.channel.html">irc.channel</a>
|
||||
</li>
|
||||
|
||||
<li><strong>irc.constants</strong></li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.ctcp.html">irc.ctcp</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.dcc.html">irc.dcc</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.debug.html">irc.debug</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.message.html">irc.message</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.misc.html">irc.misc</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<!-- File list -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div><!-- id="navigation" -->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Module <code>irc.constants</code></h1>
|
||||
|
||||
<p>This module holds various constants used by the IRC protocol.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
|
||||
</div> <!-- id="main" -->
|
||||
|
||||
<div id="about">
|
||||
<p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p>
|
||||
</div> <!-- id="about" -->
|
||||
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
117
doc/luairc/modules/irc.ctcp.html
Normal file
117
doc/luairc/modules/irc.ctcp.html
Normal file
@ -0,0 +1,117 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Reference</title>
|
||||
<link rel="stylesheet" href="../luadoc.css" type="text/css" />
|
||||
<!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
<div id="main">
|
||||
|
||||
<div id="navigation">
|
||||
|
||||
|
||||
<h1>LuaDoc</h1>
|
||||
<ul>
|
||||
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- Module list -->
|
||||
|
||||
<h1>Modules</h1>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<a href="../modules/callbacks.html">callbacks</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.html">irc</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.channel.html">irc.channel</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.constants.html">irc.constants</a>
|
||||
</li>
|
||||
|
||||
<li><strong>irc.ctcp</strong></li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.dcc.html">irc.dcc</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.debug.html">irc.debug</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.message.html">irc.message</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.misc.html">irc.misc</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<!-- File list -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div><!-- id="navigation" -->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Module <code>irc.ctcp</code></h1>
|
||||
|
||||
<p>This module implements the various quoting and escaping requirements of the CTCP protocol.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
|
||||
</div> <!-- id="main" -->
|
||||
|
||||
<div id="about">
|
||||
<p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p>
|
||||
</div> <!-- id="about" -->
|
||||
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
164
doc/luairc/modules/irc.dcc.html
Normal file
164
doc/luairc/modules/irc.dcc.html
Normal file
@ -0,0 +1,164 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Reference</title>
|
||||
<link rel="stylesheet" href="../luadoc.css" type="text/css" />
|
||||
<!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
<div id="main">
|
||||
|
||||
<div id="navigation">
|
||||
|
||||
|
||||
<h1>LuaDoc</h1>
|
||||
<ul>
|
||||
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- Module list -->
|
||||
|
||||
<h1>Modules</h1>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<a href="../modules/callbacks.html">callbacks</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.html">irc</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.channel.html">irc.channel</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.constants.html">irc.constants</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.ctcp.html">irc.ctcp</a>
|
||||
</li>
|
||||
|
||||
<li><strong>irc.dcc</strong></li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.debug.html">irc.debug</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.message.html">irc.message</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.misc.html">irc.misc</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<!-- File list -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div><!-- id="navigation" -->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Module <code>irc.dcc</code></h1>
|
||||
|
||||
<p>This module implements the DCC protocol. File transfers (DCC SEND) are handled, but DCC CHAT is not, as of yet.</p>
|
||||
|
||||
|
||||
|
||||
<h2>Functions</h2>
|
||||
<table class="function_list">
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#send">send</a> (nick, filename, port)</td>
|
||||
<td class="summary">Offers a file to a remote user.</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
<h2><a name="functions"></a>Functions</h2>
|
||||
<dl class="function">
|
||||
|
||||
|
||||
|
||||
<dt><a name="send"></a><strong>send</strong> (nick, filename, port)</dt>
|
||||
<dd>
|
||||
Offers a file to a remote user.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
nick: User to offer the file to
|
||||
</li>
|
||||
|
||||
<li>
|
||||
filename: Filename to offer
|
||||
</li>
|
||||
|
||||
<li>
|
||||
port: Port to accept connections on (optional, defaults to choosing an available port between FIRST_PORT and LAST_PORT above)
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
|
||||
</div> <!-- id="main" -->
|
||||
|
||||
<div id="about">
|
||||
<p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p>
|
||||
</div> <!-- id="about" -->
|
||||
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
196
doc/luairc/modules/irc.debug.html
Normal file
196
doc/luairc/modules/irc.debug.html
Normal file
@ -0,0 +1,196 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Reference</title>
|
||||
<link rel="stylesheet" href="../luadoc.css" type="text/css" />
|
||||
<!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
<div id="main">
|
||||
|
||||
<div id="navigation">
|
||||
|
||||
|
||||
<h1>LuaDoc</h1>
|
||||
<ul>
|
||||
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- Module list -->
|
||||
|
||||
<h1>Modules</h1>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<a href="../modules/callbacks.html">callbacks</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.html">irc</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.channel.html">irc.channel</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.constants.html">irc.constants</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.ctcp.html">irc.ctcp</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.dcc.html">irc.dcc</a>
|
||||
</li>
|
||||
|
||||
<li><strong>irc.debug</strong></li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.message.html">irc.message</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.misc.html">irc.misc</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<!-- File list -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div><!-- id="navigation" -->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Module <code>irc.debug</code></h1>
|
||||
|
||||
<p>This module implements a few useful debug functions for use throughout the rest of the code.</p>
|
||||
|
||||
|
||||
|
||||
<h2>Functions</h2>
|
||||
<table class="function_list">
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#disable">disable</a> ()</td>
|
||||
<td class="summary">Turns off debug output.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#enable">enable</a> ()</td>
|
||||
<td class="summary">Turns on debug output.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#set_output">set_output</a> (file)</td>
|
||||
<td class="summary">Redirects output to a file rather than stdout.</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
<h2><a name="functions"></a>Functions</h2>
|
||||
<dl class="function">
|
||||
|
||||
|
||||
|
||||
<dt><a name="disable"></a><strong>disable</strong> ()</dt>
|
||||
<dd>
|
||||
Turns off debug output.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="enable"></a><strong>enable</strong> ()</dt>
|
||||
<dd>
|
||||
Turns on debug output.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="set_output"></a><strong>set_output</strong> (file)</dt>
|
||||
<dd>
|
||||
Redirects output to a file rather than stdout.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
file: File to write debug output to
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
|
||||
</div> <!-- id="main" -->
|
||||
|
||||
<div id="about">
|
||||
<p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p>
|
||||
</div> <!-- id="about" -->
|
||||
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
683
doc/luairc/modules/irc.html
Normal file
683
doc/luairc/modules/irc.html
Normal file
@ -0,0 +1,683 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Reference</title>
|
||||
<link rel="stylesheet" href="../luadoc.css" type="text/css" />
|
||||
<!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
<div id="main">
|
||||
|
||||
<div id="navigation">
|
||||
|
||||
|
||||
<h1>LuaDoc</h1>
|
||||
<ul>
|
||||
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- Module list -->
|
||||
|
||||
<h1>Modules</h1>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<a href="../modules/callbacks.html">callbacks</a>
|
||||
</li>
|
||||
|
||||
<li><strong>irc</strong></li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.channel.html">irc.channel</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.constants.html">irc.constants</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.ctcp.html">irc.ctcp</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.dcc.html">irc.dcc</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.debug.html">irc.debug</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.message.html">irc.message</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.misc.html">irc.misc</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<!-- File list -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div><!-- id="navigation" -->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Module <code>irc</code></h1>
|
||||
|
||||
<p>LuaIRC - IRC framework written in Lua</p>
|
||||
|
||||
<p><small><b>Release:</b> 0.3</small></p>
|
||||
|
||||
|
||||
|
||||
<h2>Functions</h2>
|
||||
<table class="function_list">
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#act">act</a> (name, action)</td>
|
||||
<td class="summary">Perform a /me action.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#channels">channels</a> ()</td>
|
||||
<td class="summary">Iterate over currently joined channels.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#connect">connect</a> (args)</td>
|
||||
<td class="summary">Start a connection to the irc server.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#ctcp_ping">ctcp_ping</a> (cb, nick)</td>
|
||||
<td class="summary">Send a CTCP ping request.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#ctcp_time">ctcp_time</a> (cb, nick)</td>
|
||||
<td class="summary">Send a localtime request.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#ctcp_version">ctcp_version</a> (cb, nick)</td>
|
||||
<td class="summary">Send a client version request.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#get_ip">get_ip</a> ()</td>
|
||||
<td class="summary">Get the local IP address for the server connection.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#join">join</a> (channel)</td>
|
||||
<td class="summary">Join a channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#notice">notice</a> (name, message)</td>
|
||||
<td class="summary">Send a notice to a user or channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#part">part</a> (channel)</td>
|
||||
<td class="summary">Leave a channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#quit">quit</a> (message)</td>
|
||||
<td class="summary">Close the connection to the irc server.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#register_callback">register_callback</a> (name, fn)</td>
|
||||
<td class="summary">Register a user function to be called when a specific event occurs.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#say">say</a> (name, message)</td>
|
||||
<td class="summary">Send a message to a user or channel.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#send">send</a> (command, ...)</td>
|
||||
<td class="summary">Send a raw IRC command.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#server_time">server_time</a> (cb)</td>
|
||||
<td class="summary">Request the current time of the server you are connected to.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#server_version">server_version</a> (cb)</td>
|
||||
<td class="summary">Request the version of the IRC server you are currently connected to.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#set_ip">set_ip</a> (new_ip)</td>
|
||||
<td class="summary">Set the local IP manually (to allow for NAT workarounds) </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#whois">whois</a> (cb, nick)</td>
|
||||
<td class="summary">Request WHOIS information about a given user.</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
<h2><a name="functions"></a>Functions</h2>
|
||||
<dl class="function">
|
||||
|
||||
|
||||
|
||||
<dt><a name="act"></a><strong>act</strong> (name, action)</dt>
|
||||
<dd>
|
||||
Perform a /me action.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
name: User or channel to send the action to
|
||||
</li>
|
||||
|
||||
<li>
|
||||
action: Action to send
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="channels"></a><strong>channels</strong> ()</dt>
|
||||
<dd>
|
||||
Iterate over currently joined channels. channels() is an iterator function for use in for loops. For example, <pre>for chan in irc.channels() do print(chan:name) end</pre>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<em>See also:</em>
|
||||
|
||||
<a href="../modules/irc.channel.html">
|
||||
irc.channel
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="connect"></a><strong>connect</strong> (args)</dt>
|
||||
<dd>
|
||||
Start a connection to the irc server.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
args: Table of named arguments containing connection parameters. Defaults are the all-caps versions of these parameters given at the top of the file, and are overridable by setting them as well, i.e. <pre>irc.NETWORK = irc.freenode.net</pre> Possible options are: <ul> <li><i>network:</i> address of the irc network to connect to (default: 'localhost')</li> <li><i>port:</i> port to connect to (default: '6667')</li> <li><i>pass:</i> irc server password (default: don't send)</li> <li><i>nick:</i> nickname to connect as (default: 'luabot')</li> <li><i>username:</i> username to connect with (default: 'LuaIRC')</li> <li><i>realname:</i> realname to connect with (default: 'LuaIRC')</li> <li><i>timeout:</i> amount of time in seconds to wait before dropping an idle connection (default: '60')</li> </ul>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="ctcp_ping"></a><strong>ctcp_ping</strong> (cb, nick)</dt>
|
||||
<dd>
|
||||
Send a CTCP ping request.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
cb: Callback to call when the information is available. The single table parameter to this callback will contain the fields: <ul> <li><i>nick:</i> the nick which responded to the request</li> <li><i>time:</i> the roundtrip ping time, in seconds</li> </ul>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
nick: User to ping
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="ctcp_time"></a><strong>ctcp_time</strong> (cb, nick)</dt>
|
||||
<dd>
|
||||
Send a localtime request.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
cb: Callback to call when the information is available. The single table parameter to this callback will contain the fields: <ul> <li><i>nick:</i> the nick which responded to the request</li> <li><i>time:</i> the localtime reported by the remote client</li> </ul>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
nick: User to request the localtime from
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="ctcp_version"></a><strong>ctcp_version</strong> (cb, nick)</dt>
|
||||
<dd>
|
||||
Send a client version request.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
cb: Callback to call when the information is available. The single table parameter to this callback will contain the fields: <ul> <li><i>nick:</i> the nick which responded to the request</li> <li><i>version:</i> the version reported by the remote client</li> </ul>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
nick: User to request the client version from
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="get_ip"></a><strong>get_ip</strong> ()</dt>
|
||||
<dd>
|
||||
Get the local IP address for the server connection.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Return value:</h3>
|
||||
A string representation of the local IP address that the IRC server connection is communicating on
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="join"></a><strong>join</strong> (channel)</dt>
|
||||
<dd>
|
||||
Join a channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
channel: Channel to join
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="notice"></a><strong>notice</strong> (name, message)</dt>
|
||||
<dd>
|
||||
Send a notice to a user or channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
name: User or channel to send the notice to
|
||||
</li>
|
||||
|
||||
<li>
|
||||
message: Message to send
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="part"></a><strong>part</strong> (channel)</dt>
|
||||
<dd>
|
||||
Leave a channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
channel: Channel to leave
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="quit"></a><strong>quit</strong> (message)</dt>
|
||||
<dd>
|
||||
Close the connection to the irc server.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
message: Quit message (optional, defaults to 'Leaving')
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="register_callback"></a><strong>register_callback</strong> (name, fn)</dt>
|
||||
<dd>
|
||||
Register a user function to be called when a specific event occurs.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
name: Name of the event
|
||||
</li>
|
||||
|
||||
<li>
|
||||
fn: Function to call when the event occurs, or nil to clear the callback for this event
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Return value:</h3>
|
||||
Value of the original callback for this event (or nil if no previous callback had been set)
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="say"></a><strong>say</strong> (name, message)</dt>
|
||||
<dd>
|
||||
Send a message to a user or channel.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
name: User or channel to send the message to
|
||||
</li>
|
||||
|
||||
<li>
|
||||
message: Message to send
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="send"></a><strong>send</strong> (command, ...)</dt>
|
||||
<dd>
|
||||
Send a raw IRC command.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
command: String containing the raw IRC command
|
||||
</li>
|
||||
|
||||
<li>
|
||||
...: Arguments to the command. Each argument is either a string or an array. Strings are sent literally, arrays are CTCP quoted as a group. The last argument (if it exists) is preceded by a : (so it may contain spaces).
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="server_time"></a><strong>server_time</strong> (cb)</dt>
|
||||
<dd>
|
||||
Request the current time of the server you are connected to.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
cb: Callback to call when the information is available. The single table parameter to this callback will contain the fields: <ul> <li><i>server:</i> the server which responded to the request</li> <li><i>time:</i> the time reported by the server</li> </ul>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="server_version"></a><strong>server_version</strong> (cb)</dt>
|
||||
<dd>
|
||||
Request the version of the IRC server you are currently connected to.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
cb: Callback to call when the information is available. The single table parameter to this callback will contain the fields: <ul> <li><i>server:</i> the server which responded to the request</li> <li><i>version:</i> the server version</li> <li><i>comments:</i> other data provided by the server</li> </ul>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="set_ip"></a><strong>set_ip</strong> (new_ip)</dt>
|
||||
<dd>
|
||||
Set the local IP manually (to allow for NAT workarounds)
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
new_ip: IP address to set
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
|
||||
|
||||
<dt><a name="whois"></a><strong>whois</strong> (cb, nick)</dt>
|
||||
<dd>
|
||||
Request WHOIS information about a given user.
|
||||
|
||||
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
cb: Callback to call when the information is available. The single table parameter to this callback may contain any or all of the fields: <ul> <li><i>nick:</i> the nick that was passed to this function (this field will always be here)</li> <li><i>user:</i> the IRC username of the user</li> <li><i>host:</i> the user's hostname</li> <li><i>realname:</i> the IRC realname of the user</li> <li><i>server:</i> the IRC server the user is connected to</li> <li><i>serverinfo:</i> arbitrary information about the above server</li> <li><i>awaymsg:</i> set to the user's away message if they are away</li> <li><i>is_oper:</i> true if the user is an IRCop</li> <li><i>idle_time:</i> amount of time the user has been idle</li> <li><i>channels:</i> array containing the channels the user has joined</li> </ul>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
nick: User to request WHOIS information about
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
|
||||
</div> <!-- id="main" -->
|
||||
|
||||
<div id="about">
|
||||
<p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p>
|
||||
</div> <!-- id="about" -->
|
||||
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
117
doc/luairc/modules/irc.message.html
Normal file
117
doc/luairc/modules/irc.message.html
Normal file
@ -0,0 +1,117 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Reference</title>
|
||||
<link rel="stylesheet" href="../luadoc.css" type="text/css" />
|
||||
<!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
<div id="main">
|
||||
|
||||
<div id="navigation">
|
||||
|
||||
|
||||
<h1>LuaDoc</h1>
|
||||
<ul>
|
||||
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- Module list -->
|
||||
|
||||
<h1>Modules</h1>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<a href="../modules/callbacks.html">callbacks</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.html">irc</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.channel.html">irc.channel</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.constants.html">irc.constants</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.ctcp.html">irc.ctcp</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.dcc.html">irc.dcc</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.debug.html">irc.debug</a>
|
||||
</li>
|
||||
|
||||
<li><strong>irc.message</strong></li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.misc.html">irc.misc</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<!-- File list -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div><!-- id="navigation" -->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Module <code>irc.message</code></h1>
|
||||
|
||||
<p>This module contains parsing functions for IRC server messages.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
|
||||
</div> <!-- id="main" -->
|
||||
|
||||
<div id="about">
|
||||
<p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p>
|
||||
</div> <!-- id="about" -->
|
||||
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
117
doc/luairc/modules/irc.misc.html
Normal file
117
doc/luairc/modules/irc.misc.html
Normal file
@ -0,0 +1,117 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Reference</title>
|
||||
<link rel="stylesheet" href="../luadoc.css" type="text/css" />
|
||||
<!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
<div id="main">
|
||||
|
||||
<div id="navigation">
|
||||
|
||||
|
||||
<h1>LuaDoc</h1>
|
||||
<ul>
|
||||
|
||||
<li><a href="../index.html">Index</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- Module list -->
|
||||
|
||||
<h1>Modules</h1>
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<a href="../modules/callbacks.html">callbacks</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.html">irc</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.channel.html">irc.channel</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.constants.html">irc.constants</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.ctcp.html">irc.ctcp</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.dcc.html">irc.dcc</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.debug.html">irc.debug</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="../modules/irc.message.html">irc.message</a>
|
||||
</li>
|
||||
|
||||
<li><strong>irc.misc</strong></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<!-- File list -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div><!-- id="navigation" -->
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Module <code>irc.misc</code></h1>
|
||||
|
||||
<p>This module contains various useful functions which didn't fit in any of the other modules.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
|
||||
</div> <!-- id="main" -->
|
||||
|
||||
<div id="about">
|
||||
<p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p>
|
||||
</div> <!-- id="about" -->
|
||||
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
20
doc/luasocket/LICENSE
Normal file
20
doc/luasocket/LICENSE
Normal file
@ -0,0 +1,20 @@
|
||||
LuaSocket 2.0 license
|
||||
Copyright © 2004-2005 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.
|
54
doc/luasocket/NEW
Normal file
54
doc/luasocket/NEW
Normal file
@ -0,0 +1,54 @@
|
||||
What's New
|
||||
|
||||
There is no big change for the 2.0 (final) release. It is
|
||||
basically a bug fix release. The main improvement is in the
|
||||
non-blocking support.
|
||||
|
||||
* New: sample module dispatch.lua implements a coroutine
|
||||
based dispatcher;
|
||||
* New: sample check-links.lua works both in blocking and
|
||||
non-blocking mode using coroutines (using the new
|
||||
dispatcher);
|
||||
* New: sample forward.lua implements a coroutine based
|
||||
forward server (using the new dispatcher);
|
||||
* Improved: tcp:send(data, i, j) to return (i+sent-1). This
|
||||
is great for non-blocking I/O, but might break some code;
|
||||
* Improved: HTTP, SMTP, and FTP functions to accept a new
|
||||
field create that overrides the function used to create
|
||||
socket objects;
|
||||
* Improved: smtp.message now supports multipart/alternative
|
||||
(for the HTML messages we all love so much);
|
||||
* Fixed: smtp.send was hanging on errors returned by LTN12
|
||||
sources;
|
||||
* Fixed: url.absolute() to work when base_url is in parsed
|
||||
form;
|
||||
* Fixed: http.request() not to redirect when the location
|
||||
header is empty (naughty servers...);
|
||||
* Fixed: tcp{client}:shutdown() to check for class instead
|
||||
of group;
|
||||
* Fixed: The manual to stop using socket.try() in place of
|
||||
assert(), since it can't;
|
||||
* Improved: Got rid of package.loaded.base = _G kludge;
|
||||
* Fixed: Parts of the manual referred to require("http")
|
||||
instead of require("socket.http");
|
||||
* Improved: Socket and MIME binaries are called 'core' each
|
||||
inside their directory (ex. "socket/core.dll"). The 'l'
|
||||
prefix was just a bad idea;
|
||||
* Improved: Using bundles in Mac OS X, instead of dylibs;
|
||||
* Fixed: luasocket.h to export luaopen_socket_core;
|
||||
* Fixed: udp:setpeername() so you can "disconnect" an UDP
|
||||
socket;
|
||||
* Fixed: A weird bug in HTTP support that caused some
|
||||
requests to fail (Florian Berger);
|
||||
* Fixed: Bug in socket.select() that caused sockets with
|
||||
descriptor 0 to be ignored (Renato Maia);
|
||||
* Fixed: "Bug" that caused dns.toip() to crash under uLinux
|
||||
(William Trenker);
|
||||
* Fixed: "Bug" that caused gethostbyname to crash under VMS
|
||||
(Renato Maia);
|
||||
* Fixed: tcp:send("") to return 0 bytes sent (Alexander
|
||||
Marinov);
|
||||
* Improved: socket.DEBUG and socket.VERSION became
|
||||
socket._DEBUGs and socket._VERSION for uniformity with other
|
||||
libraries;
|
||||
* Improved: socket.select now works on empty sets on Windows.
|
6
doc/luasocket/README
Normal file
6
doc/luasocket/README
Normal file
@ -0,0 +1,6 @@
|
||||
This is the LuaSocket 2.0. It has been tested on WinXP, Mac OS X,
|
||||
and Linux. Please use the Lua mailing list to report any bugs
|
||||
(or "features") you encounter.
|
||||
|
||||
Have fun,
|
||||
Diego Nehab.
|
132
doc/luasocket/dns.html
Normal file
132
doc/luasocket/dns.html
Normal file
@ -0,0 +1,132 @@
|
||||
<!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="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
</center>
|
||||
<hr>
|
||||
</div>
|
||||
|
||||
<!-- dns ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<h2 id=dns>DNS</h2>
|
||||
|
||||
<p>
|
||||
Name resolution functions return <em>all</em> information obtained from the
|
||||
resolver in a table of the form:
|
||||
</p>
|
||||
|
||||
<blockquote><tt>
|
||||
resolved = {<br>
|
||||
name = <i>canonic-name</i>,<br>
|
||||
alias = <i>alias-list</i>,<br>
|
||||
ip = <i>ip-address-list</i><br>
|
||||
}
|
||||
</tt> </blockquote>
|
||||
|
||||
<p>
|
||||
Note that the <tt>alias</tt> list can be empty.
|
||||
</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 IP 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 IP 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="home.html">home</a> ·
|
||||
<a href="home.html#down">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
<p>
|
||||
<small>
|
||||
Last modified by Diego Nehab on <br>
|
||||
Mon Nov 21 01:56:09 EST 2005
|
||||
</small>
|
||||
</p>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
289
doc/luasocket/ftp.html
Normal file
289
doc/luasocket/ftp.html
Normal file
@ -0,0 +1,289 @@
|
||||
<!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="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<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.cs.princeton.edu/~diego/rfc/rfc0959.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.cs.princeton.edu/~diego/rfc/rfc1738.txt">RFC
|
||||
1738</a>, that is, an URL is a string in the form:
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<tt>
|
||||
[ftp://][<user>[:<password>]@]<host>[:<port>][/<path>][<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>PORT</tt>: default port used for the control connection;
|
||||
<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>
|
||||
host = <i>string</i>,<br>
|
||||
sink = <i>LTN12 sink</i>,<br>
|
||||
argument <i>or</i> path = <i>string</i>,<br>
|
||||
[user = <i>string</i>,]<br>
|
||||
[password = <i>string</i>]<br>
|
||||
[command = <i>string</i>,]<br>
|
||||
[port = <i>number</i>,]<br>
|
||||
[type = <i>string</i>,]<br>
|
||||
[step = <i>LTN12 pump step</i>,]<br>
|
||||
[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>
|
||||
host = <i>string</i>,<br>
|
||||
source = <i>LTN12 sink</i>,<br>
|
||||
argument <i>or</i> path = <i>string</i>,<br>
|
||||
[user = <i>string</i>,]<br>
|
||||
[password = <i>string</i>]<br>
|
||||
[command = <i>string</i>,]<br>
|
||||
[port = <i>number</i>,]<br>
|
||||
[type = <i>string</i>,]<br>
|
||||
[step = <i>LTN12 pump step</i>,]<br>
|
||||
[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="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
<p>
|
||||
<small>
|
||||
Last modified by Diego Nehab on <br>
|
||||
Mon Nov 21 01:56:32 EST 2005
|
||||
</small>
|
||||
</p>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
256
doc/luasocket/home.html
Normal file
256
doc/luasocket/home.html
Normal file
@ -0,0 +1,256 @@
|
||||
<!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="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<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 © 2004-2005 Diego Nehab. All rights reserved. <br>
|
||||
Author: <A href="http://www.cs.princeton.edu/~diego">Diego Nehab</a>
|
||||
</p>
|
||||
|
||||
<!-- download +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<h2 id=download>Download</h2>
|
||||
|
||||
<p>
|
||||
LuaSocket version 2.0 (final) is now available for download! It is
|
||||
compatible with Lua 5.0 and has been tested on
|
||||
Windows XP, Linux, and Mac OS X.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The library can be downloaded in source code from the
|
||||
<a href=http://luaforge.net/projects/luasocket/>LuaSocket
|
||||
project page</a> at LuaForge.
|
||||
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>
|
||||
Danilo Tuler is maintaining Win32 binaries for LuaSocket, which are also
|
||||
available from LuaForge. These are compatible with the
|
||||
<a href=http://luaforge.net/projects/luabinaries>LuaBinaries</a>
|
||||
available from LuaForge.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For those that want to give LuaSocket a quick try, download the
|
||||
stand-alone archive and unpack everything into
|
||||
a directory, say <tt>c:\luasocket</tt>. Then set <tt>LUA_INIT</tt> to load
|
||||
the <tt>compat-5.1.lua</tt> and set <tt>LUA_PATH</tt> and
|
||||
<tt>LUA_CPATH</tt> to look for files in the current directory:
|
||||
</p>
|
||||
|
||||
<pre class=example>
|
||||
c:\luasocket\> set LUA_INIT=@c:\luasocket\compat-5.1.lua
|
||||
c:\luasocket\> set LUA_CPATH=?.dll
|
||||
c:\luasocket\> set LUA_PATH=?.lua
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
From that directory, you can then run the interpreter and it should find all
|
||||
files it needs. To download this manual page from the Internet, for example,
|
||||
do the following:
|
||||
</p>
|
||||
|
||||
<pre class=example>
|
||||
c:\luasocket\> lua50
|
||||
Lua 5.0.2 Copyright (C) 1994-2004 Tecgraf, PUC-Rio
|
||||
> http = require"socket.http"
|
||||
> print(http.request"http://www.cs.princeton.edu/~diego/professional/luasocket/")
|
||||
--> the source to this web page gets dumped to terminal
|
||||
</pre>
|
||||
|
||||
<p> When you are done playing, 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>
|
||||
Throughout LuaSocket's history, many people gave suggestions that helped
|
||||
improve it. For that, I thank the Lua community.
|
||||
Special thanks go to
|
||||
David Burgess, who has helped push the library to a new level of quality and
|
||||
from whom I have learned a lot of stuff that doesn't show up in RFCs.
|
||||
Special thanks also to Carlos Cassino, who played a big part in the
|
||||
extensible design seen in the C core of LuaSocket 2.0. Recently, Mike Pall
|
||||
has been helping a lot too! Thanks to you all!
|
||||
</p>
|
||||
|
||||
<!-- whatsnew +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<h2 id=new>What's New</h2>
|
||||
|
||||
<p>
|
||||
There is no big change for the 2.0 (final) release. It is basically a
|
||||
bug fix release. The only improvement is in the non-blocking
|
||||
support.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li> New: sample module <tt>dispatch.lua</tt> implements a
|
||||
coroutine based dispatcher;
|
||||
<li> New: sample <tt>check-links.lua</tt> works
|
||||
both in blocking and non-blocking mode using coroutines
|
||||
(using the new dispatcher);
|
||||
<li> New: sample <tt>forward.lua</tt> implements a coroutine
|
||||
based forward server (using the new dispatcher);
|
||||
<li> Improved: <tt>tcp:send(data, i, j)</tt> to return <tt>(i+sent-1)</tt>. This is great for non-blocking I/O, but might break some code;
|
||||
<li> Improved: HTTP, SMTP, and FTP functions to accept a new field
|
||||
<tt>create</tt> that overrides the function used to create socket objects;
|
||||
<li> Improved: <tt>smtp.message</tt> now supports multipart/alternative
|
||||
(for the HTML messages we all love so much);
|
||||
<li> Fixed: <tt>smtp.send</tt> was hanging on errors returned by LTN12 sources;
|
||||
<li> Fixed: <tt>url.absolute()</tt> to work when <tt>base_url</tt> is in
|
||||
parsed form;
|
||||
<li> Fixed: <tt>http.request()</tt> not to redirect when the location
|
||||
header is empty (naughty servers...);
|
||||
<li> Fixed: <tt>tcp{client}:shutdown()</tt> to check for class instead of
|
||||
group;
|
||||
<li> Fixed: The manual to stop using <tt>socket.try()</tt> in place of
|
||||
<tt>assert()</tt>, since it can't;
|
||||
<li> Improved: Got rid of <tt>package.loaded.base = _G</tt> kludge;
|
||||
<li> Fixed: Parts of the manual referred to <tt>require("http")</tt> instead of
|
||||
<tt>require("socket.http")</tt>;
|
||||
<li> Improved: Socket and MIME binaries are called 'core' each inside their
|
||||
directory (ex. "socket/core.dll"). The 'l' prefix was just a bad idea;
|
||||
<li> Improved: Using bundles in Mac OS X, instead of dylibs;
|
||||
<li> Fixed: <tt>luasocket.h</tt> to export <tt>luaopen_socket_core</tt>;
|
||||
<li> Fixed: <tt>udp:setpeername()</tt> so you can "disconnect" an
|
||||
<tt>UDP</tt> socket;
|
||||
<li> Fixed: A weird bug in HTTP support that caused some requests to
|
||||
fail (Florian Berger);
|
||||
<li> Fixed: Bug in <tt>socket.select()</tt> that caused sockets
|
||||
with descriptor 0 to be ignored (Renato Maia);
|
||||
<li> Fixed: "Bug" that caused <tt>dns.toip()</tt> to crash under uLinux
|
||||
(William Trenker);
|
||||
<li> Fixed: "Bug" that caused <tt>gethostbyname</tt> to crash under VMS
|
||||
(Renato Maia);
|
||||
<li> Fixed: <tt>tcp:send("")</tt> to return 0 bytes sent (Alexander Marinov);
|
||||
<li> Improved: <tt>socket.DEBUG</tt> and <tt>socket.VERSION</tt> became <tt>socket._DEBUGs</tt> and <tt>socket._VERSION</tt> for uniformity with other libraries;
|
||||
<li> Improved: <tt>socket.select</tt> now works on empty sets on Windows.
|
||||
</ul>
|
||||
|
||||
<!-- incompatible +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<h3 id=incompatible>Incompatibilities with previous versions</h3>
|
||||
|
||||
<ul>
|
||||
<li> If you use the return value of <tt>tcp:send()</tt> <em>and</em> you
|
||||
use the extra parameters to select only part of the string to be sent, your
|
||||
code is now broken, but when you fix it, it will be much simpler;
|
||||
<li> If you check <tt>socket.DEBUG</tt> or <tt>socket.VERSION</tt>,
|
||||
change it to <tt>socket._DEBUG</tt> or <tt>socket._VERSION</tt>.
|
||||
</ul>
|
||||
|
||||
<!-- old ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<h2 id=old>Old Versions</h2>
|
||||
|
||||
<p>
|
||||
All previous versions of the LuaSocket library can be downloaded <a
|
||||
href="http://www.cs.princeton.edu/~diego/professional/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="home.html#down">download</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
<p>
|
||||
<small>
|
||||
Last modified by Diego Nehab on <br>
|
||||
Mon Nov 21 01:56:56 EST 2005
|
||||
</small>
|
||||
</p>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
325
doc/luasocket/http.html
Normal file
325
doc/luasocket/http.html
Normal file
@ -0,0 +1,325 @@
|
||||
<!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="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<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.cs.princeton.edu/~diego/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.cs.princeton.edu/~diego/rfc/rfc1738.txt">RFC
|
||||
1738</a>,
|
||||
that is, an URL is a string in the form:
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
[http://][<user>[:<password>]@]<host>[:<port>][/<path>]
|
||||
</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>
|
||||
field-1-name = <i>field-1-value</i>,<br>
|
||||
field-2-name = <i>field-2-value</i>,<br>
|
||||
field-3-name = <i>field-3-value</i>,<br>
|
||||
...<br>
|
||||
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.
|
||||
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>PORT</tt>: default port used for connections;
|
||||
<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>
|
||||
|
||||
<!-- http.request ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<p class=name id=request>
|
||||
http.<b>request(</b>url [, body]<b>)</b><br>
|
||||
http.<b>request{</b><br>
|
||||
url = <i>string</i>,<br>
|
||||
[sink = <i>LTN12 sink</i>,]<br>
|
||||
[method = <i>string</i>,]<br>
|
||||
[headers = <i>header-table</i>,]<br>
|
||||
[source = <i>LTN12 source</i>],<br>
|
||||
[step = <i>LTN12 pump step</i>,]<br>
|
||||
[proxy = <i>string</i>,]<br>
|
||||
[redirect = <i>boolean</i>,]<br>
|
||||
[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 complex 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.cs.princeton.edu/~diego/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=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 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.cs.princeton.edu/~diego/rfc/rfc2068.txt">RFC 2068</a>.
|
||||
</p>
|
||||
|
||||
<p class=note>The Basic Authentication Scheme sends
|
||||
<tt><user></tt> and
|
||||
<tt><password></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 = { authentication = "Basic " .. (mime.b64("fulano:silva")) }
|
||||
}
|
||||
</pre>
|
||||
|
||||
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<div class=footer>
|
||||
<hr>
|
||||
<center>
|
||||
<p class=bar>
|
||||
<a href="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
<p>
|
||||
<small>
|
||||
Last modified by Diego Nehab on <br>
|
||||
Mon Nov 21 01:57:03 EST 2005
|
||||
</small>
|
||||
</p>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
161
doc/luasocket/installation.html
Normal file
161
doc/luasocket/installation.html
Normal file
@ -0,0 +1,161 @@
|
||||
<!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="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
</center>
|
||||
<hr>
|
||||
</div>
|
||||
|
||||
<!-- installation ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<h2>Installation</h2>
|
||||
|
||||
<p> LuaSocket 2.0 uses the new package proposal for Lua 5.1.
|
||||
All Lua library developers are encouraged to update their libraries so that
|
||||
all libraries can coexist peacefully and users can benefit from the
|
||||
standardization and flexibility of the standard.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The proposal was considered important enough by some of us to justify
|
||||
early adoption, even before release of Lua 5.1.
|
||||
Thus, a compatibility module
|
||||
<a href=http://www.keplerproject.org/compat/>compat-5.1</a>
|
||||
has been released in conjunction with Roberto Ierusalimschy and <a
|
||||
href=http://www.keplerproject.org/>The Kepler Project</a> team.
|
||||
It implements the Lua 5.1 package proposal on top of Lua 5.0. </p>
|
||||
|
||||
<p> As far as LuaSocket is concerned, this means that whoever is
|
||||
deploying a non-standard distribution of LuaSocket will probably
|
||||
have no problems customizing it. Here we will only 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><CDIR></tt>
|
||||
and <tt><LDIR></tt>, respectively.
|
||||
For instance, in my laptop, I use '<tt>/usr/local/lib/lua/5.0</tt>' for
|
||||
<tt><CDIR></tt> and '<tt>/usr/local/share/lua/5.0</tt>' for
|
||||
<tt><LDIR></tt>. On Windows, sometimes only one directory is used, say
|
||||
'<tt>c:\program files\lua\5.0</tt>'. Here is the standard LuaSocket
|
||||
distribution directory structure:</p>
|
||||
|
||||
<pre class=example>
|
||||
<LDIR>/compat-5.1.lua
|
||||
<LDIR>/ltn12.lua
|
||||
<LDIR>/socket.lua
|
||||
<CDIR>/socket/core.dll
|
||||
<LDIR>/socket/http.lua
|
||||
<LDIR>/socket/tp.lua
|
||||
<LDIR>/socket/ftp.lua
|
||||
<LDIR>/socket/smtp.lua
|
||||
<LDIR>/socket/url.lua
|
||||
<LDIR>/mime.lua
|
||||
<CDIR>/mime/core.dll
|
||||
</pre>
|
||||
|
||||
<p> Naturally, on Unix systems, <tt>core.dll</tt>
|
||||
would be replaced by <tt>core.so</tt>.
|
||||
</p>
|
||||
|
||||
<p> In order for the interpreter to find all LuaSocket components, three
|
||||
environment variables need to be set. The first environment variable tells
|
||||
the interpreter to load the <tt>compat-5.1.lua</tt> module at startup: </p>
|
||||
|
||||
<pre class=example>
|
||||
LUA_INIT=@<LDIR>/compat-5.1.lua
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The other two environment variables instruct the compatibility module to
|
||||
look for dynamic libraries and extension modules in the appropriate
|
||||
directories and with the appropriate filename extensions.
|
||||
</p>
|
||||
|
||||
<pre class=example>
|
||||
LUA_PATH=<LDIR>/?.lua;?.lua
|
||||
LUA_CPATH=<CDIR>/?.dll;?.dll
|
||||
</pre>
|
||||
|
||||
<p> Again, naturally, on Unix systems the shared library extension would be
|
||||
<tt>.so</tt> instead of <tt>.dll</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.0.2 Copyright (C) 1994-2004 Tecgraf, PUC-Rio
|
||||
> socket = require("socket")
|
||||
> print(socket._VERSION)
|
||||
--> LuaSocket 2.0
|
||||
</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.0.2 Copyright (C) 1994-2004 Tecgraf, PUC-Rio
|
||||
> http = require("socket.http")
|
||||
> print(http.request("http://www.cs.princeton.edu/~diego/professional/luasocket"))
|
||||
--> homepage gets dumped to terminal
|
||||
</pre>
|
||||
|
||||
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<div class=footer>
|
||||
<hr>
|
||||
<center>
|
||||
<p class=bar>
|
||||
<a href="home.html">home</a> ·
|
||||
<a href="home.html#down">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
<p>
|
||||
<small>
|
||||
Last modified by Diego Nehab on <br>
|
||||
Mon Nov 21 01:57:22 EST 2005
|
||||
</small>
|
||||
</p>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
333
doc/luasocket/introduction.html
Normal file
333
doc/luasocket/introduction.html
Normal 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="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<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="home.html">home</a> ·
|
||||
<a href="home.html#down">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
<p>
|
||||
<small>
|
||||
Last modified by Diego Nehab on <br>
|
||||
Mon Nov 21 01:57:43 EST 2005
|
||||
</small>
|
||||
</p>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
430
doc/luasocket/ltn12.html
Normal file
430
doc/luasocket/ltn12.html
Normal 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="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<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")),
|
||||
ltn12.sink.file(io.open("copy.png"))
|
||||
)
|
||||
</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")),
|
||||
ltn12.sink.file(io.open("copy.png"))
|
||||
)
|
||||
</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="home.html">home</a> ·
|
||||
<a href="home.html#down">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
<p>
|
||||
<small>
|
||||
Last modified by Diego Nehab on <br>
|
||||
Mon Nov 21 01:57:47 EST 2005
|
||||
</small>
|
||||
</p>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
BIN
doc/luasocket/luasocket.png
Normal file
BIN
doc/luasocket/luasocket.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
476
doc/luasocket/mime.html
Normal file
476
doc/luasocket/mime.html
Normal file
@ -0,0 +1,476 @@
|
||||
<!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="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<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.cs.princeton.edu/~diego/rfc/rfc2045.txt">RFC 2045</a>,
|
||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2046.txt">2046</a>,
|
||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2047.txt">2047</a>,
|
||||
<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2047.txt">2048</a>, and
|
||||
<a href="http://www.cs.princeton.edu/~diego/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>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- 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")))
|
||||
--> 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")))
|
||||
--> ..\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çã")))
|
||||
--> 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=")))
|
||||
--> 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=")))
|
||||
--> 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="home.html">home</a> ·
|
||||
<a href="home.html#down">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
<p>
|
||||
<small>
|
||||
Last modified by Diego Nehab on <br>
|
||||
Mon Nov 21 01:57:51 EST 2005
|
||||
</small>
|
||||
</p>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
54
doc/luasocket/reference.css
Normal file
54
doc/luasocket/reference.css
Normal file
@ -0,0 +1,54 @@
|
||||
body {
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
font-family: "Verdana", sans-serif;
|
||||
}
|
||||
|
||||
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; }
|
239
doc/luasocket/reference.html
Normal file
239
doc/luasocket/reference.html
Normal file
@ -0,0 +1,239 @@
|
||||
<!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="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<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#toip">toip</a>,
|
||||
<a href="dns.html#tohostname">tohostname</a>,
|
||||
<a href="dns.html#gethostname">gethostname</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#normalize">normalize</a>,
|
||||
<a href="mime.html#decode">decode</a>,
|
||||
<a href="mime.html#encode">encode</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#wrp">wrp</a>,
|
||||
<a href="mime.html#qpwrp">qpwrp</a>.
|
||||
<a href="mime.html#unb64">unb64</a>,
|
||||
<a href="mime.html#unqp">unqp</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#debug">_DEBUG</a>,
|
||||
<a href="dns.html#dns">dns</a>,
|
||||
<a href="socket.html#gettime">gettime</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#source">source</a>,
|
||||
<a href="tcp.html#tcp">tcp</a>,
|
||||
<a href="socket.html#try">try</a>,
|
||||
<a href="udp.html#udp">udp</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#getpeername">getpeername</a>,
|
||||
<a href="tcp.html#getsockname">getsockname</a>,
|
||||
<a href="tcp.html#getstats">getstats</a>,
|
||||
<a href="tcp.html#receive">receive</a>,
|
||||
<a href="tcp.html#send">send</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#getpeername">getpeername</a>,
|
||||
<a href="udp.html#getsockname">getsockname</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="home.html">home</a> ·
|
||||
<a href="home.html#down">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
<p>
|
||||
<small>
|
||||
Last modified by Diego Nehab on <br>
|
||||
Mon Nov 21 01:57:56 EST 2005
|
||||
</small>
|
||||
</p>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
417
doc/luasocket/smtp.html
Normal file
417
doc/luasocket/smtp.html
Normal file
@ -0,0 +1,417 @@
|
||||
<!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="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<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.cs.princeton.edu/~diego/rfc/rfc2821.txt">RFC 2821</a>.
|
||||
Another RFC of interest is <a
|
||||
href="http://www.cs.princeton.edu/~diego/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.cs.princeton.edu/~diego/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>
|
||||
field-1-name = <i>field-1-value</i>,<br>
|
||||
field-2-name = <i>field-2-value</i>,<br>
|
||||
field-3-name = <i>field-3-value</i>,<br>
|
||||
...<br>
|
||||
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.
|
||||
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>
|
||||
|
||||
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<p class=name id=send>
|
||||
smtp.<b>send{</b><br>
|
||||
from = <i>string</i>,<br>
|
||||
rcpt = <i>string</i> or <i>string-table</i>,<br>
|
||||
source = <i>LTN12 source</i>,<br>
|
||||
[user = <i>string</i>,]<br>
|
||||
[password = <i>string</i>,]<br>
|
||||
[server = <i>string</i>,]<br>
|
||||
[port = <i>number</i>,]<br>
|
||||
[domain = <i>string</i>,]<br>
|
||||
[step = <i>LTN12 pump step</i>,]<br>
|
||||
[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><fulano@example.com></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.cs.princeton.edu/~diego/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.cs.princeton.edu/~diego/rfc/rfc2821.txt">RFC 2821</a>
|
||||
and
|
||||
<a href="http://www.cs.princeton.edu/~diego/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 = "<luasocket@example.com>"
|
||||
|
||||
rcpt = {
|
||||
"<fulano@example.com>",
|
||||
"<beltrano@example.com>",
|
||||
"<sicrano@example.com>"
|
||||
}
|
||||
|
||||
mesgt = {
|
||||
headers = {
|
||||
to = "Fulano da Silva <fulano@example.com>",
|
||||
cc = '"Beltrano F. Nunes" <beltrano@example.com>',
|
||||
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>
|
||||
|
||||
<!-- 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>
|
||||
headers = <i>header-table</i>,<br>
|
||||
body = <i>LTN12 source</i> or <i>string</i> or
|
||||
<i>multipart-mesgt</i><br>
|
||||
}<br>
|
||||
<br>
|
||||
multipart-mesgt = {<br>
|
||||
[preamble = <i>string</i>,]<br>
|
||||
[1] = <i>mesgt</i>,<br>
|
||||
[2] = <i>mesgt</i>,<br>
|
||||
...<br>
|
||||
[<i>n</i>] = <i>mesgt</i>,<br>
|
||||
[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 <sicrano@example.com>",
|
||||
to = "Fulano da Silva <fulano@example.com>",
|
||||
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 = "<sicrano@example.com>",
|
||||
rcpt = "<fulano@example.com>",
|
||||
source = source,
|
||||
}
|
||||
</pre>
|
||||
|
||||
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<div class=footer>
|
||||
<hr>
|
||||
<center>
|
||||
<p class=bar>
|
||||
<a href="home.html">home</a> ·
|
||||
<a href="home.html#down">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
<p>
|
||||
<small>
|
||||
Last modified by Diego Nehab on <br>
|
||||
Mon Nov 21 01:58:01 EST 2005
|
||||
</small>
|
||||
</p>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
398
doc/luasocket/socket.html
Normal file
398
doc/luasocket/socket.html
Normal file
@ -0,0 +1,398 @@
|
||||
<!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="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<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>
|
||||
|
||||
<!-- 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(</b>address, port [, locaddr, locport]<b>)</b>
|
||||
</p>
|
||||
|
||||
<p class=description>
|
||||
This function is a shortcut that creates and returns a TCP client object
|
||||
connected to a remote <tt>host</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>).
|
||||
</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>
|
||||
|
||||
<!-- 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. It will be called
|
||||
in <em>protected</em> mode.
|
||||
</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,
|
||||
returns <tt><b>nil</b></tt> followed by an error message.
|
||||
</p>
|
||||
|
||||
<p class=note>
|
||||
Note: Beware that if your function performs some illegal operation that
|
||||
raises an error, the protected function will catch the error and return it
|
||||
as a string. This is because the <a href=#try><tt>try</tt></a> function
|
||||
uses errors as the mechanism to throw exceptions.
|
||||
</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 table with the sockets ready for
|
||||
reading, a table with the sockets ready for writing and an error message.
|
||||
The error message is "<tt>timeout</tt>" if a timeout condition was met and
|
||||
<tt><b>nil</b></tt> otherwise. The returned tables are associative, to
|
||||
simplify the test if a specific socket has changed status.
|
||||
</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>
|
||||
|
||||
<!-- 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.
|
||||
The function truncates <tt>time</tt> down to the nearest integer.
|
||||
</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>
|
||||
|
||||
<!-- time ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<p class=name id=gettime>
|
||||
socket.<b>gettime()</b>
|
||||
</p>
|
||||
|
||||
<p class=description>
|
||||
Returns the time in seconds, relative to the origin of the
|
||||
universe. 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>
|
||||
|
||||
<!-- 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 of error. The exception can only be caught
|
||||
by the <a href=#protect><tt>protect</tt></a> function. It does not explode
|
||||
into an error message.
|
||||
</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>. Otherwise, it calls <tt>error</tt> passing <tt>ret</tt><sub>2</sub>.
|
||||
</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="home.html">home</a> ·
|
||||
<a href="home.html#down">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
<p>
|
||||
<small>
|
||||
Last modified by Diego Nehab on <br>
|
||||
Mon Nov 21 01:58:06 EST 2005
|
||||
</small>
|
||||
</p>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
532
doc/luasocket/tcp.html
Normal file
532
doc/luasocket/tcp.html
Normal file
@ -0,0 +1,532 @@
|
||||
<!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="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
</center>
|
||||
<hr>
|
||||
</div>
|
||||
|
||||
<!-- tcp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<h2 id=tcp>TCP</h2>
|
||||
|
||||
<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<p class=name id=socket.tcp>
|
||||
socket.<b>tcp()</b>
|
||||
</p>
|
||||
|
||||
<p class=description>
|
||||
Creates and returns a 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>
|
||||
|
||||
<!-- 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. 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>
|
||||
|
||||
<!-- 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, followed by the
|
||||
port number that peer is using for the connection.
|
||||
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 and a number with
|
||||
the port. 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>
|
||||
|
||||
<!-- 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 10), optionally preceded by a
|
||||
CR character (ASCII 13). The CR and LF characters are not included in
|
||||
the returned line. 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 which
|
||||
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.
|
||||
Also, after the error message, the function returns the partial result of
|
||||
the transmission.
|
||||
</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.
|
||||
|
||||
</ul>
|
||||
|
||||
<p class=return>
|
||||
The method returns 1 in case of success, or <b><tt>nil</tt></b> 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>
|
||||
|
||||
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<div class=footer>
|
||||
<hr>
|
||||
<center>
|
||||
<p class=bar>
|
||||
<a href="home.html">home</a> ·
|
||||
<a href="home.html#down">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
<p>
|
||||
<small>
|
||||
Last modified by Diego Nehab on <br>
|
||||
Mon Nov 21 01:58:10 EST 2005
|
||||
</small>
|
||||
</p>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
416
doc/luasocket/udp.html
Normal file
416
doc/luasocket/udp.html
Normal file
@ -0,0 +1,416 @@
|
||||
<!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="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
</center>
|
||||
<hr>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<h2 id=udp>UDP</h2>
|
||||
|
||||
<!-- 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="#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>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- 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 the IP address and port number of the peer.
|
||||
</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 and a number with the port. 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>
|
||||
|
||||
<!-- 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
|
||||
maximum datagram size is used (which is currently limited by the
|
||||
implementation to 8192 bytes).
|
||||
</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>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- 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>': Setting this option to <tt>true</tt>
|
||||
indicates that outgoing messages should bypass the standard routing
|
||||
facilities;</li>
|
||||
<li>'<tt>broadcast</tt>': Setting this option to <tt>true</tt>
|
||||
requests permission to send broadcast datagrams on the
|
||||
socket.</li>
|
||||
</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>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||
|
||||
<div class=footer>
|
||||
<hr>
|
||||
<center>
|
||||
<p class=bar>
|
||||
<a href="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
<p>
|
||||
<small>
|
||||
Last modified by Diego Nehab on <br>
|
||||
Mon Nov 21 01:58:15 EST 2005
|
||||
</small>
|
||||
</p>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
329
doc/luasocket/url.html
Normal file
329
doc/luasocket/url.html
Normal file
@ -0,0 +1,329 @@
|
||||
<!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="home.html">home</a> ·
|
||||
<a href="home.html#download">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<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.cs.princeton.edu/~diego/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>
|
||||
<url> ::= [<scheme>:][//<authority>][/<path>][;<params>][?<query>][#<fragment>]<br>
|
||||
<authority> ::= [<userinfo>@]<host>[:<port>]<br>
|
||||
<userinfo> ::= <user>[:<password>]<br>
|
||||
<path> ::= {<segment>/}<segment><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.cs.princeton.edu/~diego/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><path></tt> component from a list of
|
||||
<tt><segment></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><segment></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><path></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>
|
||||
url = <i>string</i>,<br>
|
||||
scheme = <i>string</i>,<br>
|
||||
authority = <i>string</i>,<br>
|
||||
path = <i>string</i>,<br>
|
||||
params = <i>string</i>,<br>
|
||||
query = <i>string</i>,<br>
|
||||
fragment = <i>string</i>,<br>
|
||||
userinfo = <i>string</i>,<br>
|
||||
host = <i>string</i>,<br>
|
||||
port = <i>string</i>,<br>
|
||||
user = <i>string</i>,<br>
|
||||
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><path></tt> URL component into all its
|
||||
<tt><segment></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><path></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="home.html">home</a> ·
|
||||
<a href="home.html#down">download</a> ·
|
||||
<a href="installation.html">installation</a> ·
|
||||
<a href="introduction.html">introduction</a> ·
|
||||
<a href="reference.html">reference</a>
|
||||
</p>
|
||||
<p>
|
||||
<small>
|
||||
Last modified by Diego Nehab on <br>
|
||||
Mon Nov 21 01:58:20 EST 2005
|
||||
</small>
|
||||
</p>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
50
etc/luasocket-samples/README
Normal file
50
etc/luasocket-samples/README
Normal file
@ -0,0 +1,50 @@
|
||||
This directory contains some sample programs using
|
||||
LuaSocket. This code is not supported.
|
||||
|
||||
listener.lua -- socket to stdout
|
||||
talker.lua -- stdin to socket
|
||||
|
||||
listener.lua and talker.lua are about the simplest
|
||||
applications you can write using LuaSocket. Run
|
||||
|
||||
'lua listener.lua' and 'lua talker.lua'
|
||||
|
||||
on different terminals. Whatever you type on talk.lua will
|
||||
be printed by listen.lua.
|
||||
|
||||
lpr.lua -- lpr client
|
||||
|
||||
This is a cool program written by David Burgess to print
|
||||
files using the Line Printer Daemon protocol, widely used in
|
||||
Unix machines. It uses the lp.lua implementation, in the
|
||||
etc directory. Just run 'lua lpr.lua <filename>
|
||||
queue=<printername>' and the file will print!
|
||||
|
||||
cddb.lua -- CDDB client
|
||||
|
||||
This is the first try on a simple CDDB client. Not really
|
||||
useful, but one day it might become a module.
|
||||
|
||||
daytimeclnt.lua -- day time client
|
||||
|
||||
Just run the program to retrieve the hour and date in
|
||||
readable form from any server running an UDP daytime daemon.
|
||||
|
||||
echoclnt.lua -- UDP echo client
|
||||
echosrvr.lua -- UDP echo server
|
||||
|
||||
These are a UDP echo client/server pair. They work with
|
||||
other client and servers as well.
|
||||
|
||||
tinyirc.lua -- irc like broadcast server
|
||||
|
||||
This is a simple server that waits simultaneously on two
|
||||
server sockets for telnet connections. Everything it
|
||||
receives from the telnet clients is broadcasted to every
|
||||
other connected client. It tests the select function and
|
||||
shows how to create a simple server whith LuaSocket. Just
|
||||
run tinyirc.lua and then open as many telnet connections
|
||||
as you want to ports 8080 and 8081.
|
||||
|
||||
Good luck,
|
||||
Diego.
|
46
etc/luasocket-samples/cddb.lua
Normal file
46
etc/luasocket-samples/cddb.lua
Normal file
@ -0,0 +1,46 @@
|
||||
local socket = require("socket")
|
||||
local http = require("socket.http")
|
||||
|
||||
if not arg or not arg[1] or not arg[2] then
|
||||
print("luasocket cddb.lua <category> <disc-id> [<server>]")
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
local server = arg[3] or "http://freedb.freedb.org/~cddb/cddb.cgi"
|
||||
|
||||
function parse(body)
|
||||
local lines = string.gfind(body, "(.-)\r\n")
|
||||
local status = lines()
|
||||
local code, message = socket.skip(2, string.find(status, "(%d%d%d) (.*)"))
|
||||
if tonumber(code) ~= 210 then
|
||||
return nil, code, message
|
||||
end
|
||||
local data = {}
|
||||
for l in lines do
|
||||
local c = string.sub(l, 1, 1)
|
||||
if c ~= '#' and c ~= '.' then
|
||||
local key, value = socket.skip(2, string.find(l, "(.-)=(.*)"))
|
||||
value = string.gsub(value, "\\n", "\n")
|
||||
value = string.gsub(value, "\\\\", "\\")
|
||||
value = string.gsub(value, "\\t", "\t")
|
||||
data[key] = value
|
||||
end
|
||||
end
|
||||
return data, code, message
|
||||
end
|
||||
|
||||
local host = socket.dns.gethostname()
|
||||
local query = "%s?cmd=cddb+read+%s+%s&hello=LuaSocket+%s+LuaSocket+2.0&proto=6"
|
||||
local url = string.format(query, server, arg[1], arg[2], host)
|
||||
local body, headers, code = http.get(url)
|
||||
|
||||
if code == 200 then
|
||||
local data, code, error = parse(body)
|
||||
if not data then
|
||||
print(error or code)
|
||||
else
|
||||
for i,v in pairs(data) do
|
||||
io.write(i, ': ', v, '\n')
|
||||
end
|
||||
end
|
||||
else print(error) end
|
23
etc/luasocket-samples/daytimeclnt.lua
Normal file
23
etc/luasocket-samples/daytimeclnt.lua
Normal file
@ -0,0 +1,23 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- UDP sample: daytime protocol client
|
||||
-- LuaSocket sample files
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: daytimeclnt.lua,v 1.11 2004/06/21 06:07:57 diego Exp $
|
||||
-----------------------------------------------------------------------------
|
||||
local socket = require"socket"
|
||||
host = host or "127.0.0.1"
|
||||
port = port or 13
|
||||
if arg then
|
||||
host = arg[1] or host
|
||||
port = arg[2] or port
|
||||
end
|
||||
host = socket.dns.toip(host)
|
||||
udp = socket.udp()
|
||||
print("Using host '" ..host.. "' and port " ..port.. "...")
|
||||
udp:setpeername(host, port)
|
||||
udp:settimeout(3)
|
||||
sent, err = udp:send("anything")
|
||||
if err then print(err) os.exit() end
|
||||
dgram, err = udp:receive()
|
||||
if not dgram then print(err) os.exit() end
|
||||
io.write(dgram)
|
24
etc/luasocket-samples/echoclnt.lua
Normal file
24
etc/luasocket-samples/echoclnt.lua
Normal file
@ -0,0 +1,24 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- UDP sample: echo protocol client
|
||||
-- LuaSocket sample files
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: echoclnt.lua,v 1.10 2005/01/02 22:44:00 diego Exp $
|
||||
-----------------------------------------------------------------------------
|
||||
local socket = require("socket")
|
||||
host = host or "localhost"
|
||||
port = port or 7
|
||||
if arg then
|
||||
host = arg[1] or host
|
||||
port = arg[2] or port
|
||||
end
|
||||
host = socket.dns.toip(host)
|
||||
udp = assert(socket.udp())
|
||||
assert(udp:setpeername(host, port))
|
||||
print("Using remote host '" ..host.. "' and port " .. port .. "...")
|
||||
while 1 do
|
||||
line = io.read()
|
||||
if not line or line == "" then os.exit() end
|
||||
assert(udp:send(line))
|
||||
dgram = assert(udp:receive())
|
||||
print(dgram)
|
||||
end
|
29
etc/luasocket-samples/echosrvr.lua
Normal file
29
etc/luasocket-samples/echosrvr.lua
Normal file
@ -0,0 +1,29 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- UDP sample: echo protocol server
|
||||
-- LuaSocket sample files
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: echosrvr.lua,v 1.12 2005/11/22 08:33:29 diego Exp $
|
||||
-----------------------------------------------------------------------------
|
||||
local socket = require("socket")
|
||||
host = host or "127.0.0.1"
|
||||
port = port or 7
|
||||
if arg then
|
||||
host = arg[1] or host
|
||||
port = arg[2] or port
|
||||
end
|
||||
print("Binding to host '" ..host.. "' and port " ..port.. "...")
|
||||
udp = assert(socket.udp())
|
||||
assert(udp:setsockname(host, port))
|
||||
assert(udp:settimeout(5))
|
||||
ip, port = udp:getsockname()
|
||||
assert(ip, port)
|
||||
print("Waiting packets on " .. ip .. ":" .. port .. "...")
|
||||
while 1 do
|
||||
dgram, ip, port = udp:receivefrom()
|
||||
if dgram then
|
||||
print("Echoing '" .. dgram .. "' to " .. ip .. ":" .. port)
|
||||
udp:sendto(dgram, ip, port)
|
||||
else
|
||||
print(ip)
|
||||
end
|
||||
end
|
26
etc/luasocket-samples/listener.lua
Normal file
26
etc/luasocket-samples/listener.lua
Normal file
@ -0,0 +1,26 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- TCP sample: Little program to dump lines received at a given port
|
||||
-- LuaSocket sample files
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: listener.lua,v 1.11 2005/01/02 22:44:00 diego Exp $
|
||||
-----------------------------------------------------------------------------
|
||||
local socket = require("socket")
|
||||
host = host or "*"
|
||||
port = port or 8080
|
||||
if arg then
|
||||
host = arg[1] or host
|
||||
port = arg[2] or port
|
||||
end
|
||||
print("Binding to host '" ..host.. "' and port " ..port.. "...")
|
||||
s = assert(socket.bind(host, port))
|
||||
i, p = s:getsockname()
|
||||
assert(i, p)
|
||||
print("Waiting connection from talker on " .. i .. ":" .. p .. "...")
|
||||
c = assert(s:accept())
|
||||
print("Connected. Here is the stuff:")
|
||||
l, e = c:receive()
|
||||
while not e do
|
||||
print(l)
|
||||
l, e = c:receive()
|
||||
end
|
||||
print(e)
|
51
etc/luasocket-samples/lpr.lua
Normal file
51
etc/luasocket-samples/lpr.lua
Normal file
@ -0,0 +1,51 @@
|
||||
local lp = require("socket.lp")
|
||||
|
||||
local function usage()
|
||||
print('\nUsage: lua lpr.lua [filename] [keyword=val...]\n')
|
||||
print('Valid keywords are :')
|
||||
print(
|
||||
' host=remote host or IP address (default "localhost")\n' ..
|
||||
' queue=remote queue or printer name (default "printer")\n' ..
|
||||
' port=remote port number (default 515)\n' ..
|
||||
' user=sending user name\n' ..
|
||||
' format=["binary" | "text" | "ps" | "pr" | "fortran"] (default "binary")\n' ..
|
||||
' banner=true|false\n' ..
|
||||
' indent=number of columns to indent\n' ..
|
||||
' mail=email of address to notify when print is complete\n' ..
|
||||
' title=title to use for "pr" format\n' ..
|
||||
' width=width for "text" or "pr" formats\n' ..
|
||||
' class=\n' ..
|
||||
' job=\n' ..
|
||||
' name=\n' ..
|
||||
' localbind=true|false\n'
|
||||
)
|
||||
return nil
|
||||
end
|
||||
|
||||
if not arg or not arg[1] then
|
||||
return usage()
|
||||
end
|
||||
|
||||
do
|
||||
local opt = {}
|
||||
local pat = "[%s%c%p]*([%w]*)=([\"]?[%w%s_!@#$%%^&*()<>:;]+[\"]\?\.?)"
|
||||
for i = 2, table.getn(arg), 1 do
|
||||
string.gsub(arg[i], pat, function(name, value) opt[name] = value end)
|
||||
end
|
||||
if not arg[2] then
|
||||
return usage()
|
||||
end
|
||||
if arg[1] ~= "query" then
|
||||
opt.file = arg[1]
|
||||
r,e=lp.send(opt)
|
||||
io.stdout:write(tostring(r or e),'\n')
|
||||
else
|
||||
r,e=lp.query(opt)
|
||||
io.stdout:write(tostring(r or e), '\n')
|
||||
end
|
||||
end
|
||||
|
||||
-- trivial tests
|
||||
--lua lp.lua lp.lua queue=default host=localhost
|
||||
--lua lp.lua lp.lua queue=default host=localhost format=binary localbind=1
|
||||
--lua lp.lua query queue=default host=localhost
|
21
etc/luasocket-samples/talker.lua
Normal file
21
etc/luasocket-samples/talker.lua
Normal file
@ -0,0 +1,21 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- TCP sample: Little program to send text lines to a given host/port
|
||||
-- LuaSocket sample files
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: talker.lua,v 1.9 2005/01/02 22:44:00 diego Exp $
|
||||
-----------------------------------------------------------------------------
|
||||
local socket = require("socket")
|
||||
host = host or "localhost"
|
||||
port = port or 8080
|
||||
if arg then
|
||||
host = arg[1] or host
|
||||
port = arg[2] or port
|
||||
end
|
||||
print("Attempting connection to host '" ..host.. "' and port " ..port.. "...")
|
||||
c = assert(socket.connect(host, port))
|
||||
print("Connected! Please type stuff (empty line to stop):")
|
||||
l = io.read()
|
||||
while l and l ~= "" and not e do
|
||||
assert(c:send(l .. "\n"))
|
||||
l = io.read()
|
||||
end
|
90
etc/luasocket-samples/tinyirc.lua
Normal file
90
etc/luasocket-samples/tinyirc.lua
Normal file
@ -0,0 +1,90 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- Select sample: simple text line server
|
||||
-- LuaSocket sample files.
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: tinyirc.lua,v 1.14 2005/11/22 08:33:29 diego Exp $
|
||||
-----------------------------------------------------------------------------
|
||||
local socket = require("socket")
|
||||
host = host or "*"
|
||||
port1 = port1 or 8080
|
||||
port2 = port2 or 8181
|
||||
if arg then
|
||||
host = arg[1] or host
|
||||
port1 = arg[2] or port1
|
||||
port2 = arg[3] or port2
|
||||
end
|
||||
|
||||
server1 = assert(socket.bind(host, port1))
|
||||
server2 = assert(socket.bind(host, port2))
|
||||
server1:settimeout(1) -- make sure we don't block in accept
|
||||
server2:settimeout(1)
|
||||
|
||||
io.write("Servers bound\n")
|
||||
|
||||
-- simple set implementation
|
||||
-- the select function doesn't care about what is passed to it as long as
|
||||
-- it behaves like a table
|
||||
-- creates a new set data structure
|
||||
function newset()
|
||||
local reverse = {}
|
||||
local set = {}
|
||||
return setmetatable(set, {__index = {
|
||||
insert = function(set, value)
|
||||
if not reverse[value] then
|
||||
table.insert(set, value)
|
||||
reverse[value] = table.getn(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
|
||||
|
||||
set = newset()
|
||||
|
||||
io.write("Inserting servers in set\n")
|
||||
set:insert(server1)
|
||||
set:insert(server2)
|
||||
|
||||
while 1 do
|
||||
local readable, _, error = socket.select(set, nil)
|
||||
for _, input in ipairs(readable) do
|
||||
-- is it a server socket?
|
||||
if input == server1 or input == server2 then
|
||||
io.write("Waiting for clients\n")
|
||||
local new = input:accept()
|
||||
if new then
|
||||
new:settimeout(1)
|
||||
io.write("Inserting client in set\n")
|
||||
set:insert(new)
|
||||
end
|
||||
-- it is a client socket
|
||||
else
|
||||
local line, error = input:receive()
|
||||
if error then
|
||||
input:close()
|
||||
io.write("Removing client from set\n")
|
||||
set:remove(input)
|
||||
else
|
||||
io.write("Broadcasting line '", line, "'\n")
|
||||
writable, error = socket.skip(1, socket.select(nil, set, 1))
|
||||
if not error then
|
||||
for __, output in ipairs(writable) do
|
||||
if output ~= input then
|
||||
output:send(line .. "\n")
|
||||
end
|
||||
end
|
||||
else io.write("No client ready to receive!!!\n") end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
89
etc/luasocket/README
Normal file
89
etc/luasocket/README
Normal 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. You can
|
||||
also use the '-n' switch to run the same program in
|
||||
non-blocking mode to see how much faster things can get.
|
||||
|
||||
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.
|
20
etc/luasocket/b64.lua
Normal file
20
etc/luasocket/b64.lua
Normal file
@ -0,0 +1,20 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- Little program to convert to and from Base64
|
||||
-- LuaSocket sample files
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: b64.lua,v 1.8 2004/06/16 04:28:21 diego Exp $
|
||||
-----------------------------------------------------------------------------
|
||||
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)
|
112
etc/luasocket/check-links.lua
Normal file
112
etc/luasocket/check-links.lua
Normal file
@ -0,0 +1,112 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- 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
|
||||
-- RCS ID: $$
|
||||
-----------------------------------------------------------------------------
|
||||
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 table.getn(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
|
17
etc/luasocket/check-memory.lua
Normal file
17
etc/luasocket/check-memory.lua
Normal 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")
|
152
etc/luasocket/dict.lua
Normal file
152
etc/luasocket/dict.lua
Normal file
@ -0,0 +1,152 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- Little program to download DICT word definitions
|
||||
-- LuaSocket sample files
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: dict.lua,v 1.22 2005/11/22 08:33:29 diego Exp $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- 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)
|
||||
|
301
etc/luasocket/dispatch.lua
Normal file
301
etc/luasocket/dispatch.lua
Normal file
@ -0,0 +1,301 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- A hacked dispatcher module
|
||||
-- LuaSocket sample files
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $$
|
||||
-----------------------------------------------------------------------------
|
||||
local base = _G
|
||||
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, so we rewrite it with coxpcall
|
||||
-- make sure you don't require any module that uses socket.protect before
|
||||
-- loading our hack
|
||||
function socket.protect(f)
|
||||
return function(...)
|
||||
local co = coroutine.create(f)
|
||||
while true do
|
||||
local results = {coroutine.resume(co, unpack(arg))}
|
||||
local status = table.remove(results, 1)
|
||||
if not status then
|
||||
if type(results[1]) == 'table' then
|
||||
return nil, results[1][1]
|
||||
else error(results[1]) end
|
||||
end
|
||||
if coroutine.status(co) == "suspended" then
|
||||
arg = {coroutine.yield(unpack(results))}
|
||||
else
|
||||
return unpack(results)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Simple set data structure. O(1) everything.
|
||||
-----------------------------------------------------------------------------
|
||||
local function newset()
|
||||
local reverse = {}
|
||||
local set = {}
|
||||
return setmetatable(set, {__index = {
|
||||
insert = function(set, value)
|
||||
if not reverse[value] then
|
||||
table.insert(set, value)
|
||||
reverse[value] = table.getn(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(...)
|
||||
arg[1] = tcp
|
||||
return tcp[key](unpack(arg))
|
||||
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 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 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 ipairs(readable) do
|
||||
schedule(wakeup(self.receiving, tcp))
|
||||
end
|
||||
-- for all writable connections, do the same
|
||||
for _, tcp in 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 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 setmetatable(dispatcher, cometat)
|
||||
end
|
||||
|
14
etc/luasocket/eol.lua
Normal file
14
etc/luasocket/eol.lua
Normal file
@ -0,0 +1,14 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- Little program to adjust end of line markers.
|
||||
-- LuaSocket sample files
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: eol.lua,v 1.8 2005/11/22 08:33:29 diego Exp $
|
||||
-----------------------------------------------------------------------------
|
||||
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)
|
65
etc/luasocket/forward.lua
Normal file
65
etc/luasocket/forward.lua
Normal 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 table.getn(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
|
140
etc/luasocket/get.lua
Normal file
140
etc/luasocket/get.lua
Normal file
@ -0,0 +1,140 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- Little program to download files from URLs
|
||||
-- LuaSocket sample files
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: get.lua,v 1.24 2005/11/22 08:33:29 diego Exp $
|
||||
-----------------------------------------------------------------------------
|
||||
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 got = 0
|
||||
return function(chunk)
|
||||
-- elapsed time since start
|
||||
local delta = socket.gettime() - start
|
||||
if chunk then
|
||||
-- total bytes received
|
||||
got = got + string.len(chunk)
|
||||
-- not enough time for estimate
|
||||
if delta > 0.1 then
|
||||
io.stderr:write("\r", gauge(got, delta, size))
|
||||
io.stderr:flush()
|
||||
end
|
||||
else
|
||||
-- close up
|
||||
io.stderr:write("\r", gauge(got, delta), "\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 table.getn(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
|
324
etc/luasocket/lp.lua
Normal file
324
etc/luasocket/lp.lua
Normal file
@ -0,0 +1,324 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- LPD support for the Lua language
|
||||
-- LuaSocket toolkit.
|
||||
-- Author: David Burgess
|
||||
-- Modified by Diego Nehab, but David is in charge
|
||||
-- RCS ID: $Id: lp.lua,v 1.14 2005/11/21 07:04:44 diego Exp $
|
||||
-----------------------------------------------------------------------------
|
||||
--[[
|
||||
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)
|
24
etc/luasocket/qp.lua
Normal file
24
etc/luasocket/qp.lua
Normal file
@ -0,0 +1,24 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- Little program to convert to and from Quoted-Printable
|
||||
-- LuaSocket sample files
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: qp.lua,v 1.5 2004/06/17 21:46:22 diego Exp $
|
||||
-----------------------------------------------------------------------------
|
||||
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)
|
155
etc/luasocket/tftp.lua
Normal file
155
etc/luasocket/tftp.lua
Normal file
@ -0,0 +1,155 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- TFTP support for the Lua language
|
||||
-- LuaSocket toolkit.
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: tftp.lua,v 1.16 2005/11/22 08:33:29 diego Exp $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- 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)
|
||||
|
109
etc/tests/luairc/luabot.lua
Executable file
109
etc/tests/luairc/luabot.lua
Executable file
@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env lua
|
||||
|
||||
local irc = require 'irc'
|
||||
irc.DEBUG = true
|
||||
|
||||
local nick = "doylua"
|
||||
|
||||
local envs = {}
|
||||
|
||||
local function create_env()
|
||||
return {
|
||||
_VERSION = _VERSION,
|
||||
assert = assert,
|
||||
collectgarbage = collectgarbage,
|
||||
error = error,
|
||||
getfenv = getfenv,
|
||||
getmetatable = getmetatable,
|
||||
ipairs = ipairs,
|
||||
loadstring = loadstring,
|
||||
next = next,
|
||||
pairs = pairs,
|
||||
pcall = pcall,
|
||||
rawequal = rawequal,
|
||||
rawget = rawget,
|
||||
rawset = rawset,
|
||||
select = select,
|
||||
setfenv = setfenv,
|
||||
setmetatable = setmetatable,
|
||||
tonumber = tonumber,
|
||||
tostring = tostring,
|
||||
type = type,
|
||||
unpack = unpack,
|
||||
xpcall = xpcall,
|
||||
coroutine = coroutine,
|
||||
math = math,
|
||||
string = string,
|
||||
table = table,
|
||||
}
|
||||
end
|
||||
|
||||
local commands = {
|
||||
eval = function(target, from, code)
|
||||
code = code:gsub("^=", "return ")
|
||||
local fn, err = loadstring(code)
|
||||
if not fn then
|
||||
irc.say(target, from .. ": Error loading code: " .. code .. err:match(".*(:.-)$"))
|
||||
return
|
||||
else
|
||||
setfenv(fn, envs[from])
|
||||
local result = {pcall(fn)}
|
||||
local success = table.remove(result, 1)
|
||||
if not success then
|
||||
irc.say(target, from .. ": Error running code: " .. code .. result[1]:match(".*(:.-)$"))
|
||||
else
|
||||
if result[1] == nil then
|
||||
irc.say(target, from .. ": nil")
|
||||
else
|
||||
irc.say(target, from .. ": " .. table.concat(result, ", "))
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
clear = function(target, from)
|
||||
irc.say(target, from .. ": Clearing your environment")
|
||||
envs[from] = create_env()
|
||||
end,
|
||||
help = function(target, from, arg)
|
||||
if arg == "" or not arg then
|
||||
irc.say(target, from .. ": Commands: !clear, !eval, !help")
|
||||
elseif arg == "eval" then
|
||||
irc.say(target, from .. ": Evaluates a Lua statement in your own persistent environment")
|
||||
elseif arg == "clear" then
|
||||
irc.say(target, from .. ": Clears your personal environment")
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
irc.register_callback("connect", function()
|
||||
irc.join("#doytest")
|
||||
end)
|
||||
|
||||
irc.register_callback("channel_msg", function(channel, from, message)
|
||||
message = message:gsub("^" .. nick .. "[:,>] ", "!eval ")
|
||||
local is_cmd, cmd, arg = message:match("^(!)([%w_]+) ?(.-)$")
|
||||
if is_cmd and commands[cmd] then
|
||||
envs[from] = envs[from] or create_env()
|
||||
commands[cmd](channel.name, from, arg)
|
||||
end
|
||||
end)
|
||||
|
||||
irc.register_callback("private_msg", function(from, message)
|
||||
message = message:gsub("^" .. nick .. "[:,>] ", "!eval ")
|
||||
local is_cmd, cmd, arg = message:match("^(!)([%w_]+) ?(.-)$")
|
||||
envs[from] = envs[from] or create_env()
|
||||
if is_cmd and commands[cmd] then
|
||||
commands[cmd](from, from, arg)
|
||||
else
|
||||
commands["eval"](from, from, message)
|
||||
end
|
||||
end)
|
||||
|
||||
irc.register_callback("nick_change", function(from, old_nick)
|
||||
if envs[old_nick] and not envs[from] then
|
||||
envs[from] = envs[old_nick]
|
||||
envs[old_nick] = nil
|
||||
end
|
||||
end)
|
||||
|
||||
irc.connect{network = "irc.freenode.net", nick = nick, pass = "doylua"}
|
228
etc/tests/luairc/test.lua
Executable file
228
etc/tests/luairc/test.lua
Executable file
@ -0,0 +1,228 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local irc = require "irc"
|
||||
local dcc = require "irc.dcc"
|
||||
|
||||
irc.DEBUG = true
|
||||
|
||||
local ip_prog = io.popen("get_ip")
|
||||
local ip = ip_prog:read()
|
||||
ip_prog:close()
|
||||
irc.set_ip(ip)
|
||||
|
||||
local function print_state()
|
||||
for chan in irc.channels() do
|
||||
print(chan..": Channel ops: "..table.concat(chan:ops(), " "))
|
||||
print(chan..": Channel voices: "..table.concat(chan:voices(), " "))
|
||||
print(chan..": Channel normal users: "..table.concat(chan:users(), " "))
|
||||
print(chan..": All channel members: "..table.concat(chan:members(), " "))
|
||||
end
|
||||
end
|
||||
|
||||
local function on_connect()
|
||||
print("Joining channel #doytest...")
|
||||
irc.join("#doytest")
|
||||
print("Joining channel #doytest2...")
|
||||
irc.join("#doytest2")
|
||||
end
|
||||
irc.register_callback("connect", on_connect)
|
||||
|
||||
local function on_me_join(chan)
|
||||
print("Join to " .. chan .. " complete.")
|
||||
print(chan .. ": Channel type: " .. chan.chanmode)
|
||||
if chan.topic.text and chan.topic.text ~= "" then
|
||||
print(chan .. ": Channel topic: " .. chan.topic.text)
|
||||
print(" Set by " .. chan.topic.user ..
|
||||
" at " .. os.date("%c", chan.topic.time))
|
||||
end
|
||||
irc.act(chan.name, "is here")
|
||||
print_state()
|
||||
end
|
||||
irc.register_callback("me_join", on_me_join)
|
||||
|
||||
local function on_join(chan, user)
|
||||
print("I saw a join to " .. chan)
|
||||
if tostring(user) ~= "doylua" then
|
||||
irc.say(tostring(chan), "Hi, " .. user)
|
||||
end
|
||||
print_state()
|
||||
end
|
||||
irc.register_callback("join", on_join)
|
||||
|
||||
local function on_part(chan, user, part_msg)
|
||||
print("I saw a part from " .. chan .. " saying " .. part_msg)
|
||||
print_state()
|
||||
end
|
||||
irc.register_callback("part", on_part)
|
||||
|
||||
local function on_nick_change(new_nick, old_nick)
|
||||
print("I saw a nick change: " .. old_nick .. " -> " .. new_nick)
|
||||
print_state()
|
||||
end
|
||||
irc.register_callback("nick_change", on_nick_change)
|
||||
|
||||
local function on_kick(chan, user)
|
||||
print("I saw a kick in " .. chan)
|
||||
print_state()
|
||||
end
|
||||
irc.register_callback("kick", on_kick)
|
||||
|
||||
local function on_quit(chan, user)
|
||||
print("I saw a quit from " .. chan)
|
||||
print_state()
|
||||
end
|
||||
irc.register_callback("quit", on_quit)
|
||||
|
||||
local function whois_cb(cb_data)
|
||||
print("WHOIS data for " .. cb_data.nick)
|
||||
if cb_data.user then print("Username: " .. cb_data.user) end
|
||||
if cb_data.host then print("Host: " .. cb_data.host) end
|
||||
if cb_data.realname then print("Realname: " .. cb_data.realname) end
|
||||
if cb_data.server then print("Server: " .. cb_data.server) end
|
||||
if cb_data.serverinfo then print("Serverinfo: " .. cb_data.serverinfo) end
|
||||
if cb_data.away_msg then print("Awaymsg: " .. cb_data.away_msg) end
|
||||
if cb_data.is_oper then print(nick .. "is an IRCop") end
|
||||
if cb_data.idle_time then print("Idletime: " .. cb_data.idle_time) end
|
||||
if cb_data.channels then
|
||||
print("Channel list for " .. cb_data.nick .. ":")
|
||||
for _, channel in ipairs(cb_data.channels) do print(channel) end
|
||||
end
|
||||
end
|
||||
|
||||
local function serverversion_cb(cb_data)
|
||||
print("VERSION data for " .. cb_data.server)
|
||||
print("Version: " .. cb_data.version)
|
||||
print("Comments: " .. cb_data.comments)
|
||||
end
|
||||
|
||||
local function ping_cb(cb_data)
|
||||
print("CTCP PING for " .. cb_data.nick)
|
||||
print("Roundtrip time: " .. cb_data.time .. "s")
|
||||
end
|
||||
|
||||
local function time_cb(cb_data)
|
||||
print("CTCP TIME for " .. cb_data.nick)
|
||||
print("Localtime: " .. cb_data.time)
|
||||
end
|
||||
|
||||
local function version_cb(cb_data)
|
||||
print("CTCP VERSION for " .. cb_data.nick)
|
||||
print("Version: " .. cb_data.version)
|
||||
end
|
||||
|
||||
local function stime_cb(cb_data)
|
||||
print("TIME for " .. cb_data.server)
|
||||
print("Server time: " .. cb_data.time)
|
||||
end
|
||||
|
||||
local function on_channel_msg(chan, from, msg)
|
||||
if from == "doy" then
|
||||
if msg == "leave" then
|
||||
irc.part(chan.name)
|
||||
return
|
||||
elseif msg:sub(1, 3) == "op " then
|
||||
chan:op(msg:sub(4))
|
||||
return
|
||||
elseif msg:sub(1, 5) == "deop " then
|
||||
chan:deop(msg:sub(6))
|
||||
return
|
||||
elseif msg:sub(1, 6) == "voice " then
|
||||
chan:voice(msg:sub(7))
|
||||
return
|
||||
elseif msg:sub(1, 8) == "devoice " then
|
||||
chan:devoice(msg:sub(9))
|
||||
return
|
||||
elseif msg:sub(1, 5) == "kick " then
|
||||
chan:kick(msg:sub(6))
|
||||
return
|
||||
elseif msg:sub(1, 5) == "send " then
|
||||
dcc.send(from, msg:sub(6))
|
||||
return
|
||||
elseif msg:sub(1, 6) == "whois " then
|
||||
irc.whois(whois_cb, msg:sub(7))
|
||||
return
|
||||
elseif msg:sub(1, 8) == "sversion" then
|
||||
irc.server_version(serverversion_cb)
|
||||
return
|
||||
elseif msg:sub(1, 5) == "ping " then
|
||||
irc.ctcp_ping(ping_cb, msg:sub(6))
|
||||
return
|
||||
elseif msg:sub(1, 5) == "time " then
|
||||
irc.ctcp_time(time_cb, msg:sub(6))
|
||||
return
|
||||
elseif msg:sub(1, 8) == "version " then
|
||||
irc.ctcp_version(version_cb, msg:sub(9))
|
||||
return
|
||||
elseif msg:sub(1, 5) == "stime" then
|
||||
irc.server_time(stime_cb)
|
||||
return
|
||||
elseif msg:sub(1, 6) == "trace " then
|
||||
irc.trace(trace_cb, msg:sub(7))
|
||||
return
|
||||
elseif msg:sub(1, 5) == "trace" then
|
||||
irc.trace(trace_cb)
|
||||
return
|
||||
end
|
||||
end
|
||||
if from ~= "doylua" then
|
||||
irc.say(chan.name, from .. ": " .. msg)
|
||||
end
|
||||
end
|
||||
irc.register_callback("channel_msg", on_channel_msg)
|
||||
|
||||
local function on_private_msg(from, msg)
|
||||
if from == "doy" then
|
||||
if msg == "leave" then
|
||||
irc.quit("gone")
|
||||
return
|
||||
elseif msg:sub(1, 5) == "send " then
|
||||
dcc.send(from, msg:sub(6))
|
||||
return
|
||||
end
|
||||
end
|
||||
if from ~= "doylua" then
|
||||
irc.say(from, msg)
|
||||
end
|
||||
end
|
||||
irc.register_callback("private_msg", on_private_msg)
|
||||
|
||||
local function on_channel_act(chan, from, msg)
|
||||
irc.act(chan.name, "jumps on " .. from)
|
||||
end
|
||||
irc.register_callback("channel_act", on_channel_act)
|
||||
|
||||
local function on_private_act(from, msg)
|
||||
irc.act(from, "jumps on you")
|
||||
end
|
||||
irc.register_callback("private_act", on_private_act)
|
||||
|
||||
local function on_op(chan, from, nick)
|
||||
print(nick .. " was opped in " .. chan .. " by " .. from)
|
||||
print_state()
|
||||
end
|
||||
irc.register_callback("op", on_op)
|
||||
|
||||
local function on_deop(chan, from, nick)
|
||||
print(nick .. " was deopped in " .. chan .. " by " .. from)
|
||||
print_state()
|
||||
end
|
||||
irc.register_callback("deop", on_deop)
|
||||
|
||||
local function on_voice(chan, from, nick)
|
||||
print(nick .. " was voiced in " .. chan .. " by " .. from)
|
||||
print_state()
|
||||
end
|
||||
irc.register_callback("voice", on_voice)
|
||||
|
||||
local function on_devoice(chan, from, nick)
|
||||
print(nick .. " was devoiced in " .. chan .. " by " .. from)
|
||||
print_state()
|
||||
end
|
||||
irc.register_callback("devoice", on_devoice)
|
||||
|
||||
local function on_dcc_send()
|
||||
return true
|
||||
end
|
||||
irc.register_callback("dcc_send", on_dcc_send)
|
||||
|
||||
irc.connect{network = "irc.freenode.net", nick = "doylua"}
|
12
etc/tests/luasocket/README
Normal file
12
etc/tests/luasocket/README
Normal file
@ -0,0 +1,12 @@
|
||||
This provides the automated test scripts used to make sure the library
|
||||
is working properly.
|
||||
|
||||
The files provided are:
|
||||
|
||||
testsrvr.lua -- test server
|
||||
testclnt.lua -- test client
|
||||
|
||||
To run these tests, just run lua on the server and then on the client.
|
||||
|
||||
Good luck,
|
||||
Diego.
|
655
etc/tests/luasocket/testclnt.lua
Normal file
655
etc/tests/luasocket/testclnt.lua
Normal file
@ -0,0 +1,655 @@
|
||||
local socket = require"socket"
|
||||
|
||||
host = host or "localhost"
|
||||
port = port or "8383"
|
||||
|
||||
function pass(...)
|
||||
local s = string.format(unpack(arg))
|
||||
io.stderr:write(s, "\n")
|
||||
end
|
||||
|
||||
function fail(...)
|
||||
local s = string.format(unpack(arg))
|
||||
io.stderr:write("ERROR: ", s, "!\n")
|
||||
socket.sleep(3)
|
||||
os.exit()
|
||||
end
|
||||
|
||||
function warn(...)
|
||||
local s = string.format(unpack(arg))
|
||||
io.stderr:write("WARNING: ", s, "\n")
|
||||
end
|
||||
|
||||
function remote(...)
|
||||
local s = string.format(unpack(arg))
|
||||
s = string.gsub(s, "\n", ";")
|
||||
s = string.gsub(s, "%s+", " ")
|
||||
s = string.gsub(s, "^%s*", "")
|
||||
control:send(s .. "\n")
|
||||
control:receive()
|
||||
end
|
||||
|
||||
function test(test)
|
||||
io.stderr:write("----------------------------------------------\n",
|
||||
"testing: ", test, "\n",
|
||||
"----------------------------------------------\n")
|
||||
end
|
||||
|
||||
function check_timeout(tm, sl, elapsed, err, opp, mode, alldone)
|
||||
if tm < sl then
|
||||
if opp == "send" then
|
||||
if not err then warn("must be buffered")
|
||||
elseif err == "timeout" then pass("proper timeout")
|
||||
else fail("unexpected error '%s'", err) end
|
||||
else
|
||||
if err ~= "timeout" then fail("should have timed out")
|
||||
else pass("proper timeout") end
|
||||
end
|
||||
else
|
||||
if mode == "total" then
|
||||
if elapsed > tm then
|
||||
if err ~= "timeout" then fail("should have timed out")
|
||||
else pass("proper timeout") end
|
||||
elseif elapsed < tm then
|
||||
if err then fail(err)
|
||||
else pass("ok") end
|
||||
else
|
||||
if alldone then
|
||||
if err then fail("unexpected error '%s'", err)
|
||||
else pass("ok") end
|
||||
else
|
||||
if err ~= "timeout" then fail(err)
|
||||
else pass("proper timeoutk") end
|
||||
end
|
||||
end
|
||||
else
|
||||
if err then fail(err)
|
||||
else pass("ok") end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not socket._DEBUG then
|
||||
fail("Please define LUASOCKET_DEBUG and recompile LuaSocket")
|
||||
end
|
||||
|
||||
io.stderr:write("----------------------------------------------\n",
|
||||
"LuaSocket Test Procedures\n",
|
||||
"----------------------------------------------\n")
|
||||
|
||||
start = socket.gettime()
|
||||
|
||||
function reconnect()
|
||||
io.stderr:write("attempting data connection... ")
|
||||
if data then data:close() end
|
||||
remote [[
|
||||
if data then data:close() data = nil end
|
||||
data = server:accept()
|
||||
data:setoption("tcp-nodelay", true)
|
||||
]]
|
||||
data, err = socket.connect(host, port)
|
||||
if not data then fail(err)
|
||||
else pass("connected!") end
|
||||
data:setoption("tcp-nodelay", true)
|
||||
end
|
||||
|
||||
pass("attempting control connection...")
|
||||
control, err = socket.connect(host, port)
|
||||
if err then fail(err)
|
||||
else pass("connected!") end
|
||||
control:setoption("tcp-nodelay", true)
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function test_methods(sock, methods)
|
||||
for _, v in methods do
|
||||
if type(sock[v]) ~= "function" then
|
||||
fail(sock.class .. " method '" .. v .. "' not registered")
|
||||
end
|
||||
end
|
||||
pass(sock.class .. " methods are ok")
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function test_mixed(len)
|
||||
reconnect()
|
||||
local inter = math.ceil(len/4)
|
||||
local p1 = "unix " .. string.rep("x", inter) .. "line\n"
|
||||
local p2 = "dos " .. string.rep("y", inter) .. "line\r\n"
|
||||
local p3 = "raw " .. string.rep("z", inter) .. "bytes"
|
||||
local p4 = "end" .. string.rep("w", inter) .. "bytes"
|
||||
local bp1, bp2, bp3, bp4
|
||||
remote (string.format("str = data:receive(%d)",
|
||||
string.len(p1)+string.len(p2)+string.len(p3)+string.len(p4)))
|
||||
sent, err = data:send(p1..p2..p3..p4)
|
||||
if err then fail(err) end
|
||||
remote "data:send(str); data:close()"
|
||||
bp1, err = data:receive()
|
||||
if err then fail(err) end
|
||||
bp2, err = data:receive()
|
||||
if err then fail(err) end
|
||||
bp3, err = data:receive(string.len(p3))
|
||||
if err then fail(err) end
|
||||
bp4, err = data:receive("*a")
|
||||
if err then fail(err) end
|
||||
if bp1.."\n" == p1 and bp2.."\r\n" == p2 and bp3 == p3 and bp4 == p4 then
|
||||
pass("patterns match")
|
||||
else fail("patterns don't match") end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function test_asciiline(len)
|
||||
reconnect()
|
||||
local str, str10, back, err
|
||||
str = string.rep("x", math.mod(len, 10))
|
||||
str10 = string.rep("aZb.c#dAe?", math.floor(len/10))
|
||||
str = str .. str10
|
||||
remote "str = data:receive()"
|
||||
sent, err = data:send(str.."\n")
|
||||
if err then fail(err) end
|
||||
remote "data:send(str ..'\\n')"
|
||||
back, err = data:receive()
|
||||
if err then fail(err) end
|
||||
if back == str then pass("lines match")
|
||||
else fail("lines don't match") end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function test_rawline(len)
|
||||
reconnect()
|
||||
local str, str10, back, err
|
||||
str = string.rep(string.char(47), math.mod(len, 10))
|
||||
str10 = string.rep(string.char(120,21,77,4,5,0,7,36,44,100),
|
||||
math.floor(len/10))
|
||||
str = str .. str10
|
||||
remote "str = data:receive()"
|
||||
sent, err = data:send(str.."\n")
|
||||
if err then fail(err) end
|
||||
remote "data:send(str..'\\n')"
|
||||
back, err = data:receive()
|
||||
if err then fail(err) end
|
||||
if back == str then pass("lines match")
|
||||
else fail("lines don't match") end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function test_raw(len)
|
||||
reconnect()
|
||||
local half = math.floor(len/2)
|
||||
local s1, s2, back, err
|
||||
s1 = string.rep("x", half)
|
||||
s2 = string.rep("y", len-half)
|
||||
remote (string.format("str = data:receive(%d)", len))
|
||||
sent, err = data:send(s1)
|
||||
if err then fail(err) end
|
||||
sent, err = data:send(s2)
|
||||
if err then fail(err) end
|
||||
remote "data:send(str)"
|
||||
back, err = data:receive(len)
|
||||
if err then fail(err) end
|
||||
if back == s1..s2 then pass("blocks match")
|
||||
else fail("blocks don't match") end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function test_totaltimeoutreceive(len, tm, sl)
|
||||
reconnect()
|
||||
local str, err, partial
|
||||
pass("%d bytes, %ds total timeout, %ds pause", len, tm, sl)
|
||||
remote (string.format ([[
|
||||
data:settimeout(%d)
|
||||
str = string.rep('a', %d)
|
||||
data:send(str)
|
||||
print('server: sleeping for %ds')
|
||||
socket.sleep(%d)
|
||||
print('server: woke up')
|
||||
data:send(str)
|
||||
]], 2*tm, len, sl, sl))
|
||||
data:settimeout(tm, "total")
|
||||
local t = socket.gettime()
|
||||
str, err, partial, elapsed = data:receive(2*len)
|
||||
check_timeout(tm, sl, elapsed, err, "receive", "total",
|
||||
string.len(str or partial) == 2*len)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function test_totaltimeoutsend(len, tm, sl)
|
||||
reconnect()
|
||||
local str, err, total
|
||||
pass("%d bytes, %ds total timeout, %ds pause", len, tm, sl)
|
||||
remote (string.format ([[
|
||||
data:settimeout(%d)
|
||||
str = data:receive(%d)
|
||||
print('server: sleeping for %ds')
|
||||
socket.sleep(%d)
|
||||
print('server: woke up')
|
||||
str = data:receive(%d)
|
||||
]], 2*tm, len, sl, sl, len))
|
||||
data:settimeout(tm, "total")
|
||||
str = string.rep("a", 2*len)
|
||||
total, err, partial, elapsed = data:send(str)
|
||||
check_timeout(tm, sl, elapsed, err, "send", "total",
|
||||
total == 2*len)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function test_blockingtimeoutreceive(len, tm, sl)
|
||||
reconnect()
|
||||
local str, err, partial
|
||||
pass("%d bytes, %ds blocking timeout, %ds pause", len, tm, sl)
|
||||
remote (string.format ([[
|
||||
data:settimeout(%d)
|
||||
str = string.rep('a', %d)
|
||||
data:send(str)
|
||||
print('server: sleeping for %ds')
|
||||
socket.sleep(%d)
|
||||
print('server: woke up')
|
||||
data:send(str)
|
||||
]], 2*tm, len, sl, sl))
|
||||
data:settimeout(tm)
|
||||
str, err, partial, elapsed = data:receive(2*len)
|
||||
check_timeout(tm, sl, elapsed, err, "receive", "blocking",
|
||||
string.len(str or partial) == 2*len)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function test_blockingtimeoutsend(len, tm, sl)
|
||||
reconnect()
|
||||
local str, err, total
|
||||
pass("%d bytes, %ds blocking timeout, %ds pause", len, tm, sl)
|
||||
remote (string.format ([[
|
||||
data:settimeout(%d)
|
||||
str = data:receive(%d)
|
||||
print('server: sleeping for %ds')
|
||||
socket.sleep(%d)
|
||||
print('server: woke up')
|
||||
str = data:receive(%d)
|
||||
]], 2*tm, len, sl, sl, len))
|
||||
data:settimeout(tm)
|
||||
str = string.rep("a", 2*len)
|
||||
total, err, partial, elapsed = data:send(str)
|
||||
check_timeout(tm, sl, elapsed, err, "send", "blocking",
|
||||
total == 2*len)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function empty_connect()
|
||||
reconnect()
|
||||
if data then data:close() data = nil end
|
||||
remote [[
|
||||
if data then data:close() data = nil end
|
||||
data = server:accept()
|
||||
]]
|
||||
data, err = socket.connect("", port)
|
||||
if not data then
|
||||
pass("ok")
|
||||
data = socket.connect(host, port)
|
||||
else
|
||||
pass("gethostbyname returns localhost on empty string...")
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function isclosed(c)
|
||||
return c:getfd() == -1 or c:getfd() == (2^32-1)
|
||||
end
|
||||
|
||||
function active_close()
|
||||
reconnect()
|
||||
if isclosed(data) then fail("should not be closed") end
|
||||
data:close()
|
||||
if not isclosed(data) then fail("should be closed") end
|
||||
data = nil
|
||||
local udp = socket.udp()
|
||||
if isclosed(udp) then fail("should not be closed") end
|
||||
udp:close()
|
||||
if not isclosed(udp) then fail("should be closed") end
|
||||
pass("ok")
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function test_closed()
|
||||
local back, partial, err
|
||||
local str = 'little string'
|
||||
reconnect()
|
||||
pass("trying read detection")
|
||||
remote (string.format ([[
|
||||
data:send('%s')
|
||||
data:close()
|
||||
data = nil
|
||||
]], str))
|
||||
-- try to get a line
|
||||
back, err, partial = data:receive()
|
||||
if not err then fail("should have gotten 'closed'.")
|
||||
elseif err ~= "closed" then fail("got '"..err.."' instead of 'closed'.")
|
||||
elseif str ~= partial then fail("didn't receive partial result.")
|
||||
else pass("graceful 'closed' received") end
|
||||
reconnect()
|
||||
pass("trying write detection")
|
||||
remote [[
|
||||
data:close()
|
||||
data = nil
|
||||
]]
|
||||
total, err, partial = data:send(string.rep("ugauga", 100000))
|
||||
if not err then
|
||||
pass("failed: output buffer is at least %d bytes long!", total)
|
||||
elseif err ~= "closed" then
|
||||
fail("got '"..err.."' instead of 'closed'.")
|
||||
else
|
||||
pass("graceful 'closed' received after %d bytes were sent", partial)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function test_selectbugs()
|
||||
local r, s, e = socket.select(nil, nil, 0.1)
|
||||
assert(type(r) == "table" and type(s) == "table" and
|
||||
(e == "timeout" or e == "error"))
|
||||
pass("both nil: ok")
|
||||
local udp = socket.udp()
|
||||
udp:close()
|
||||
r, s, e = socket.select({ udp }, { udp }, 0.1)
|
||||
assert(type(r) == "table" and type(s) == "table" and
|
||||
(e == "timeout" or e == "error"))
|
||||
pass("closed sockets: ok")
|
||||
e = pcall(socket.select, "wrong", 1, 0.1)
|
||||
assert(e == false)
|
||||
e = pcall(socket.select, {}, 1, 0.1)
|
||||
assert(e == false)
|
||||
pass("invalid input: ok")
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function accept_timeout()
|
||||
io.stderr:write("accept with timeout (if it hangs, it failed): ")
|
||||
local s, e = socket.bind("*", 0, 0)
|
||||
assert(s, e)
|
||||
local t = socket.gettime()
|
||||
s:settimeout(1)
|
||||
local c, e = s:accept()
|
||||
assert(not c, "should not accept")
|
||||
assert(e == "timeout", string.format("wrong error message (%s)", e))
|
||||
t = socket.gettime() - t
|
||||
assert(t < 2, string.format("took to long to give up (%gs)", t))
|
||||
s:close()
|
||||
pass("good")
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function connect_timeout()
|
||||
io.stderr:write("connect with timeout (if it hangs, it failed!): ")
|
||||
local t = socket.gettime()
|
||||
local c, e = socket.tcp()
|
||||
assert(c, e)
|
||||
c:settimeout(0.1)
|
||||
local t = socket.gettime()
|
||||
local r, e = c:connect("10.0.0.1", 81)
|
||||
print(r, e)
|
||||
assert(not r, "should not connect")
|
||||
assert(socket.gettime() - t < 2, "took too long to give up.")
|
||||
c:close()
|
||||
print("ok")
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function accept_errors()
|
||||
io.stderr:write("not listening: ")
|
||||
local d, e = socket.bind("*", 0)
|
||||
assert(d, e);
|
||||
local c, e = socket.tcp();
|
||||
assert(c, e);
|
||||
d:setfd(c:getfd())
|
||||
d:settimeout(2)
|
||||
local r, e = d:accept()
|
||||
assert(not r and e)
|
||||
print("ok: ", e)
|
||||
io.stderr:write("not supported: ")
|
||||
local c, e = socket.udp()
|
||||
assert(c, e);
|
||||
d:setfd(c:getfd())
|
||||
local r, e = d:accept()
|
||||
assert(not r and e)
|
||||
print("ok: ", e)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function connect_errors()
|
||||
io.stderr:write("connection refused: ")
|
||||
local c, e = socket.connect("localhost", 1);
|
||||
assert(not c and e)
|
||||
print("ok: ", e)
|
||||
io.stderr:write("host not found: ")
|
||||
local c, e = socket.connect("host.is.invalid", 1);
|
||||
assert(not c and e, e)
|
||||
print("ok: ", e)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function rebind_test()
|
||||
local c = socket.bind("localhost", 0)
|
||||
local i, p = c:getsockname()
|
||||
local s, e = socket.tcp()
|
||||
assert(s, e)
|
||||
s:setoption("reuseaddr", false)
|
||||
r, e = s:bind("localhost", p)
|
||||
assert(not r, "managed to rebind!")
|
||||
assert(e)
|
||||
print("ok: ", e)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function getstats_test()
|
||||
reconnect()
|
||||
local t = 0
|
||||
for i = 1, 25 do
|
||||
local c = math.random(1, 100)
|
||||
remote (string.format ([[
|
||||
str = data:receive(%d)
|
||||
data:send(str)
|
||||
]], c))
|
||||
data:send(string.rep("a", c))
|
||||
data:receive(c)
|
||||
t = t + c
|
||||
local r, s, a = data:getstats()
|
||||
assert(r == t, "received count failed" .. tostring(r)
|
||||
.. "/" .. tostring(t))
|
||||
assert(s == t, "sent count failed" .. tostring(s)
|
||||
.. "/" .. tostring(t))
|
||||
end
|
||||
print("ok")
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function test_nonblocking(size)
|
||||
reconnect()
|
||||
print("Testing " .. 2*size .. " bytes")
|
||||
remote(string.format([[
|
||||
data:send(string.rep("a", %d))
|
||||
socket.sleep(0.5)
|
||||
data:send(string.rep("b", %d) .. "\n")
|
||||
]], size, size))
|
||||
local err = "timeout"
|
||||
local part = ""
|
||||
local str
|
||||
data:settimeout(0)
|
||||
while 1 do
|
||||
str, err, part = data:receive("*l", part)
|
||||
if err ~= "timeout" then break end
|
||||
end
|
||||
assert(str == (string.rep("a", size) .. string.rep("b", size)))
|
||||
reconnect()
|
||||
remote(string.format([[
|
||||
str = data:receive(%d)
|
||||
socket.sleep(0.5)
|
||||
str = data:receive(2*%d, str)
|
||||
data:send(str)
|
||||
]], size, size))
|
||||
data:settimeout(0)
|
||||
local start = 0
|
||||
while 1 do
|
||||
ret, err, start = data:send(str, start+1)
|
||||
if err ~= "timeout" then break end
|
||||
end
|
||||
data:send("\n")
|
||||
data:settimeout(-1)
|
||||
local back = data:receive(2*size)
|
||||
assert(back == str, "'" .. back .. "' vs '" .. str .. "'")
|
||||
print("ok")
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
test("method registration")
|
||||
test_methods(socket.tcp(), {
|
||||
"accept",
|
||||
"bind",
|
||||
"close",
|
||||
"connect",
|
||||
"dirty",
|
||||
"getfd",
|
||||
"getpeername",
|
||||
"getsockname",
|
||||
"getstats",
|
||||
"setstats",
|
||||
"listen",
|
||||
"receive",
|
||||
"send",
|
||||
"setfd",
|
||||
"setoption",
|
||||
"setpeername",
|
||||
"setsockname",
|
||||
"settimeout",
|
||||
"shutdown",
|
||||
})
|
||||
|
||||
test_methods(socket.udp(), {
|
||||
"close",
|
||||
"getpeername",
|
||||
"dirty",
|
||||
"getfd",
|
||||
"getpeername",
|
||||
"getsockname",
|
||||
"receive",
|
||||
"receivefrom",
|
||||
"send",
|
||||
"sendto",
|
||||
"setfd",
|
||||
"setoption",
|
||||
"setpeername",
|
||||
"setsockname",
|
||||
"settimeout"
|
||||
})
|
||||
|
||||
test("select function")
|
||||
test_selectbugs()
|
||||
|
||||
test("connect function")
|
||||
connect_timeout()
|
||||
empty_connect()
|
||||
connect_errors()
|
||||
|
||||
test("rebinding: ")
|
||||
rebind_test()
|
||||
|
||||
test("active close: ")
|
||||
active_close()
|
||||
|
||||
test("closed connection detection: ")
|
||||
test_closed()
|
||||
|
||||
test("accept function: ")
|
||||
accept_timeout()
|
||||
accept_errors()
|
||||
|
||||
test("getstats test")
|
||||
getstats_test()
|
||||
|
||||
test("character line")
|
||||
test_asciiline(1)
|
||||
test_asciiline(17)
|
||||
test_asciiline(200)
|
||||
test_asciiline(4091)
|
||||
test_asciiline(80199)
|
||||
test_asciiline(8000000)
|
||||
test_asciiline(80199)
|
||||
test_asciiline(4091)
|
||||
test_asciiline(200)
|
||||
test_asciiline(17)
|
||||
test_asciiline(1)
|
||||
|
||||
test("mixed patterns")
|
||||
test_mixed(1)
|
||||
test_mixed(17)
|
||||
test_mixed(200)
|
||||
test_mixed(4091)
|
||||
test_mixed(801990)
|
||||
test_mixed(4091)
|
||||
test_mixed(200)
|
||||
test_mixed(17)
|
||||
test_mixed(1)
|
||||
|
||||
test("binary line")
|
||||
test_rawline(1)
|
||||
test_rawline(17)
|
||||
test_rawline(200)
|
||||
test_rawline(4091)
|
||||
test_rawline(80199)
|
||||
test_rawline(8000000)
|
||||
test_rawline(80199)
|
||||
test_rawline(4091)
|
||||
test_rawline(200)
|
||||
test_rawline(17)
|
||||
test_rawline(1)
|
||||
|
||||
test("raw transfer")
|
||||
test_raw(1)
|
||||
test_raw(17)
|
||||
test_raw(200)
|
||||
test_raw(4091)
|
||||
test_raw(80199)
|
||||
test_raw(8000000)
|
||||
test_raw(80199)
|
||||
test_raw(4091)
|
||||
test_raw(200)
|
||||
test_raw(17)
|
||||
test_raw(1)
|
||||
|
||||
test("non-blocking transfer")
|
||||
test_nonblocking(1)
|
||||
test_nonblocking(17)
|
||||
test_nonblocking(200)
|
||||
test_nonblocking(4091)
|
||||
test_nonblocking(80199)
|
||||
test_nonblocking(800000)
|
||||
test_nonblocking(80199)
|
||||
test_nonblocking(4091)
|
||||
test_nonblocking(200)
|
||||
test_nonblocking(17)
|
||||
test_nonblocking(1)
|
||||
|
||||
test("total timeout on send")
|
||||
test_totaltimeoutsend(800091, 1, 3)
|
||||
test_totaltimeoutsend(800091, 2, 3)
|
||||
test_totaltimeoutsend(800091, 5, 2)
|
||||
test_totaltimeoutsend(800091, 3, 1)
|
||||
|
||||
test("total timeout on receive")
|
||||
test_totaltimeoutreceive(800091, 1, 3)
|
||||
test_totaltimeoutreceive(800091, 2, 3)
|
||||
test_totaltimeoutreceive(800091, 3, 2)
|
||||
test_totaltimeoutreceive(800091, 3, 1)
|
||||
|
||||
test("blocking timeout on send")
|
||||
test_blockingtimeoutsend(800091, 1, 3)
|
||||
test_blockingtimeoutsend(800091, 2, 3)
|
||||
test_blockingtimeoutsend(800091, 3, 2)
|
||||
test_blockingtimeoutsend(800091, 3, 1)
|
||||
|
||||
test("blocking timeout on receive")
|
||||
test_blockingtimeoutreceive(800091, 1, 3)
|
||||
test_blockingtimeoutreceive(800091, 2, 3)
|
||||
test_blockingtimeoutreceive(800091, 3, 2)
|
||||
test_blockingtimeoutreceive(800091, 3, 1)
|
||||
|
||||
test(string.format("done in %.2fs", socket.gettime() - start))
|
15
etc/tests/luasocket/testsrvr.lua
Normal file
15
etc/tests/luasocket/testsrvr.lua
Normal file
@ -0,0 +1,15 @@
|
||||
socket = require("socket");
|
||||
host = host or "localhost";
|
||||
port = port or "8383";
|
||||
server = assert(socket.bind(host, port));
|
||||
ack = "\n";
|
||||
while 1 do
|
||||
print("server: waiting for client connection...");
|
||||
control = assert(server:accept());
|
||||
while 1 do
|
||||
command = assert(control:receive());
|
||||
assert(control:send(ack));
|
||||
print(command);
|
||||
(loadstring(command))();
|
||||
end
|
||||
end
|
37
etc/tests/luasocket/testsupport.lua
Normal file
37
etc/tests/luasocket/testsupport.lua
Normal file
@ -0,0 +1,37 @@
|
||||
function readfile(name)
|
||||
local f = io.open(name, "rb")
|
||||
if not f then return nil end
|
||||
local s = f:read("*a")
|
||||
f:close()
|
||||
return s
|
||||
end
|
||||
|
||||
function similar(s1, s2)
|
||||
return string.lower(string.gsub(s1 or "", "%s", "")) ==
|
||||
string.lower(string.gsub(s2 or "", "%s", ""))
|
||||
end
|
||||
|
||||
function fail(msg)
|
||||
msg = msg or "failed"
|
||||
error(msg, 2)
|
||||
end
|
||||
|
||||
function compare(input, output)
|
||||
local original = readfile(input)
|
||||
local recovered = readfile(output)
|
||||
if original ~= recovered then fail("comparison failed")
|
||||
else print("ok") end
|
||||
end
|
||||
|
||||
local G = _G
|
||||
local set = rawset
|
||||
local warn = print
|
||||
|
||||
local setglobal = function(table, key, value)
|
||||
warn("changed " .. key)
|
||||
set(table, key, value)
|
||||
end
|
||||
|
||||
setmetatable(G, {
|
||||
__newindex = setglobal
|
||||
})
|
71
packmod.sh
Normal file
71
packmod.sh
Normal file
@ -0,0 +1,71 @@
|
||||
#! /bin/sh
|
||||
|
||||
echo "Detecting directories...";
|
||||
if [ -f "CMakeLists.txt" ]; then
|
||||
srcdir=".";
|
||||
bindir="Build";
|
||||
elif [ -f "../CMakeLists.txt" ]; then
|
||||
srcdir="..";
|
||||
bindir=".";
|
||||
else
|
||||
echo "Error: Couldn't find CMakeLists.txt." >&2;
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
if [ -e "$bindir/src/luasocket/libluasocket.dll" ]; then
|
||||
lib="$bindir/src/luasocket/libluasocket.dll;
|
||||
elif [ -e "$bindir/src/luasocket/libluasocket.so" ]; then
|
||||
lib="$bindir/src/luasocket/libluasocket.so;
|
||||
else
|
||||
echo "Error: Couldn't find luasocket lib." >&2;
|
||||
echo " Did you compile before running this script?" >&2;
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
version="`cat "$srcdir/CMakeLists.txt" \
|
||||
| grep 'MINETEST_IRC_VERSION' \
|
||||
| sed -e 's/^set(MINETEST_IRC_VERSION \([^)]*\)/\1/'`";
|
||||
|
||||
mkdir "$srcdir/irc-$version";
|
||||
|
||||
files_luairc="\
|
||||
$srcdir/src/luairc/irc.lua
|
||||
$srcdir/src/luairc/irc/channel.lua
|
||||
$srcdir/src/luairc/irc/constants.lua
|
||||
$srcdir/src/luairc/irc/ctcp.lua
|
||||
$srcdir/src/luairc/irc/dcc.lua
|
||||
$srcdir/src/luairc/irc/debug.lua
|
||||
$srcdir/src/luairc/irc/message.lua
|
||||
$srcdir/src/luairc/irc/misc.lua
|
||||
";
|
||||
|
||||
files_luasocket="\
|
||||
$srcdir/src/luasocket/ftp.lua
|
||||
$srcdir/src/luasocket/http.lua
|
||||
$srcdir/src/luasocket/ltn12.lua
|
||||
$srcdir/src/luasocket/mime.lua
|
||||
$srcdir/src/luasocket/smtp.lua
|
||||
$srcdir/src/luasocket/socket.lua
|
||||
$srcdir/src/luasocket/tp.lua
|
||||
$srcdir/src/luasocket/url.lua
|
||||
$lib
|
||||
";
|
||||
|
||||
files="\
|
||||
$srcdir/src/init.lua
|
||||
$files_luairc
|
||||
$files_luasocket
|
||||
";
|
||||
|
||||
oIFS="$IFS";
|
||||
IFS='
|
||||
';
|
||||
|
||||
echo "Copying files...";
|
||||
for file in $files; do
|
||||
IFS="$oIFS";
|
||||
cp "$file" "$srcdir/irc-$version/";
|
||||
done
|
||||
|
||||
echo "Operation completed successfully!";
|
||||
exit 0;
|
5
src/CMakeLists.txt
Normal file
5
src/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
# :mode=cmake:noTabs=true:
|
||||
|
||||
add_subdirectory(lua)
|
||||
add_subdirectory(luasocket)
|
0
src/dummy.c
Normal file
0
src/dummy.c
Normal file
118
src/init.lua
Normal file
118
src/init.lua
Normal file
@ -0,0 +1,118 @@
|
||||
|
||||
-- IRC Mod for Minetest
|
||||
-- (C) 2012 Diego Martínez <kaeza@users.sf.net>
|
||||
--
|
||||
-- This mod allows to tie a Minetest server to an IRC channel.
|
||||
--
|
||||
-- This program is free software. It comes without any warranty, to
|
||||
-- the extent permitted by applicable law. You can redistribute it
|
||||
-- and/or modify it under the terms of the Do What The Fuck You Want
|
||||
-- To Public License, Version 2, as published by Sam Hocevar. See
|
||||
-- http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
--
|
||||
|
||||
-- *************************
|
||||
-- ** BEGIN USER SETTINGS **
|
||||
-- *************************
|
||||
|
||||
-- Server to connect on joinplayer (string, default "irc.freenode.net")
|
||||
local SERVER = "irc.freenode.net";
|
||||
|
||||
-- Channel to connect on joinplayer (string, default "#minetest-irc-testing")
|
||||
local CHANNEL = "#minetest-irc-testing";
|
||||
|
||||
-- Time between chat updates in seconds (number, default 0.2).
|
||||
local DTIME = 0.5;
|
||||
|
||||
-- Enable debug output (boolean, default false)
|
||||
local DEBUG = false;
|
||||
|
||||
local SERVER_NICK = "mt_game";
|
||||
|
||||
-- ***********************
|
||||
-- ** END USER SETTINGS **
|
||||
-- ***********************
|
||||
|
||||
-- **********************************************************************
|
||||
-- ** DO NOT EDIT ANYTHING BELOW UNLESS YOU KNOW WHAT YOU ARE DOING!!! **
|
||||
-- **********************************************************************
|
||||
|
||||
|
||||
local MODPATH = minetest.get_modpath("irc");
|
||||
|
||||
package.path = MODPATH.."/?.lua;"..package.path;
|
||||
package.cpath = MODPATH.."/lib?.so;"..MODPATH.."/?.dll;"..package.cpath;
|
||||
|
||||
local irc = require 'irc';
|
||||
|
||||
irc.DEBUG = ((DEBUG and true) or false);
|
||||
|
||||
-- This could be made local.
|
||||
mt_irc = {
|
||||
cur_time = 0;
|
||||
buffered_messages = { };
|
||||
};
|
||||
|
||||
SERVER = (SERVER or "irc.freenode.net");
|
||||
CHANNEL = (CHANNEL or "#minetest-irc-testing");
|
||||
DTIME = (DTIME or 0.2);
|
||||
|
||||
minetest.register_globalstep(function ( dtime )
|
||||
mt_irc.cur_time = mt_irc.cur_time + dtime;
|
||||
if (mt_irc.cur_time >= DTIME) then
|
||||
if (mt_irc.buffered_messages) then
|
||||
for _, t in ipairs(mt_irc.buffered_messages) do
|
||||
irc.say(CHANNEL, "<"..t.name.."> "..(t.message or ""));
|
||||
end
|
||||
mt_irc.buffered_messages = nil;
|
||||
end
|
||||
irc.poll();
|
||||
mt_irc.cur_time = mt_irc.cur_time - DTIME;
|
||||
local plys = minetest.get_connected_players();
|
||||
if (#plys <= 0) then -- Just in case :)
|
||||
irc.quit("Closing.");
|
||||
end
|
||||
end
|
||||
end);
|
||||
|
||||
minetest.register_on_joinplayer(function ( player )
|
||||
|
||||
print("PLAYER JOINED: "..player:get_player_name());
|
||||
minetest.chat_send_all("PLAYER JOINED: "..player:get_player_name());
|
||||
|
||||
irc.register_callback("connect", function ( )
|
||||
irc.join(CHANNEL);
|
||||
end);
|
||||
|
||||
irc.register_callback("channel_msg", function ( channel, from, message )
|
||||
minetest.chat_send_all(from.."[IRC:"..channel.."]: "..message);
|
||||
end);
|
||||
|
||||
irc.register_callback("private_msg", function ( from, message )
|
||||
end);
|
||||
|
||||
irc.register_callback("nick_change", function ( from, old_nick )
|
||||
end);
|
||||
|
||||
end);
|
||||
|
||||
minetest.register_on_leaveplayer(function ( player )
|
||||
irc.say(CHANNEL, "*** "..player:get_player_name().." left the game");
|
||||
end);
|
||||
|
||||
minetest.register_on_chat_message(function ( name, message )
|
||||
if (not mt_irc.buffered_messages) then
|
||||
mt_irc.buffered_messages = { };
|
||||
end
|
||||
mt_irc.buffered_messages[#mt_irc.buffered_messages + 1] = {
|
||||
name = name;
|
||||
message = message;
|
||||
};
|
||||
end);
|
||||
|
||||
irc.connect({
|
||||
network = SERVER;
|
||||
nick = SERVER_NICK;
|
||||
pass = "1234";
|
||||
timeout = 1.0;
|
||||
});
|
16
src/lua/CMakeLists.txt
Normal file
16
src/lua/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
# :mode=cmake:noTabs=true:tabSize=4:
|
||||
|
||||
set(LUA_SRCS
|
||||
lapi.c lcode.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c
|
||||
lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c
|
||||
lundump.c lvm.c lzio.c
|
||||
lauxlib.c lbaselib.c ldblib.c liolib.c lmathlib.c loslib.c ltablib.c
|
||||
lstrlib.c loadlib.c linit.c
|
||||
)
|
||||
|
||||
add_library(lua_lib ${LUA_SRCS})
|
||||
set_target_properties(lua_lib
|
||||
PROPERTIES
|
||||
OUTPUT_NAME lua51-minetest-irc
|
||||
)
|
1077
src/lua/lapi.c
Normal file
1077
src/lua/lapi.c
Normal file
File diff suppressed because it is too large
Load Diff
16
src/lua/lapi.h
Normal file
16
src/lua/lapi.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
** $Id: lapi.h,v 2.2 2005/04/25 19:24:10 roberto Exp $
|
||||
** Auxiliary functions from Lua API
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef lapi_h
|
||||
#define lapi_h
|
||||
|
||||
|
||||
#include "lobject.h"
|
||||
|
||||
|
||||
LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o);
|
||||
|
||||
#endif
|
647
src/lua/lauxlib.c
Normal file
647
src/lua/lauxlib.c
Normal file
@ -0,0 +1,647 @@
|
||||
/*
|
||||
** $Id: lauxlib.c,v 1.158 2006/01/16 12:42:21 roberto Exp $
|
||||
** Auxiliary functions for building Lua libraries
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/* This file uses only the official API of Lua.
|
||||
** Any function declared here could be written as an application function.
|
||||
*/
|
||||
|
||||
#define lauxlib_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lauxlib.h"
|
||||
|
||||
|
||||
#define FREELIST_REF 0 /* free list of references */
|
||||
|
||||
|
||||
/* convert a stack index to positive */
|
||||
#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \
|
||||
lua_gettop(L) + (i) + 1)
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Error-report functions
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
|
||||
LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) {
|
||||
lua_Debug ar;
|
||||
if (!lua_getstack(L, 0, &ar)) /* no stack frame? */
|
||||
return luaL_error(L, "bad argument #%d (%s)", narg, extramsg);
|
||||
lua_getinfo(L, "n", &ar);
|
||||
if (strcmp(ar.namewhat, "method") == 0) {
|
||||
narg--; /* do not count `self' */
|
||||
if (narg == 0) /* error is in the self argument itself? */
|
||||
return luaL_error(L, "calling " LUA_QS " on bad self (%s)",
|
||||
ar.name, extramsg);
|
||||
}
|
||||
if (ar.name == NULL)
|
||||
ar.name = "?";
|
||||
return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)",
|
||||
narg, ar.name, extramsg);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) {
|
||||
const char *msg = lua_pushfstring(L, "%s expected, got %s",
|
||||
tname, luaL_typename(L, narg));
|
||||
return luaL_argerror(L, narg, msg);
|
||||
}
|
||||
|
||||
|
||||
static void tag_error (lua_State *L, int narg, int tag) {
|
||||
luaL_typerror(L, narg, lua_typename(L, tag));
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_where (lua_State *L, int level) {
|
||||
lua_Debug ar;
|
||||
if (lua_getstack(L, level, &ar)) { /* check function at level */
|
||||
lua_getinfo(L, "Sl", &ar); /* get info about it */
|
||||
if (ar.currentline > 0) { /* is there info? */
|
||||
lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
|
||||
return;
|
||||
}
|
||||
}
|
||||
lua_pushliteral(L, ""); /* else, no information available... */
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
|
||||
va_list argp;
|
||||
va_start(argp, fmt);
|
||||
luaL_where(L, 1);
|
||||
lua_pushvfstring(L, fmt, argp);
|
||||
va_end(argp);
|
||||
lua_concat(L, 2);
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def,
|
||||
const char *const lst[]) {
|
||||
const char *name = (def) ? luaL_optstring(L, narg, def) :
|
||||
luaL_checkstring(L, narg);
|
||||
int i;
|
||||
for (i=0; lst[i]; i++)
|
||||
if (strcmp(lst[i], name) == 0)
|
||||
return i;
|
||||
return luaL_argerror(L, narg,
|
||||
lua_pushfstring(L, "invalid option " LUA_QS, name));
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get registry.name */
|
||||
if (!lua_isnil(L, -1)) /* name already in use? */
|
||||
return 0; /* leave previous value on top, but return 0 */
|
||||
lua_pop(L, 1);
|
||||
lua_newtable(L); /* create metatable */
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {
|
||||
void *p = lua_touserdata(L, ud);
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */
|
||||
if (p == NULL || !lua_getmetatable(L, ud) || !lua_rawequal(L, -1, -2))
|
||||
luaL_typerror(L, ud, tname);
|
||||
lua_pop(L, 2); /* remove both metatables */
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) {
|
||||
if (!lua_checkstack(L, space))
|
||||
luaL_error(L, "stack overflow (%s)", mes);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) {
|
||||
if (lua_type(L, narg) != t)
|
||||
tag_error(L, narg, t);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_checkany (lua_State *L, int narg) {
|
||||
if (lua_type(L, narg) == LUA_TNONE)
|
||||
luaL_argerror(L, narg, "value expected");
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) {
|
||||
const char *s = lua_tolstring(L, narg, len);
|
||||
if (!s) tag_error(L, narg, LUA_TSTRING);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API const char *luaL_optlstring (lua_State *L, int narg,
|
||||
const char *def, size_t *len) {
|
||||
if (lua_isnoneornil(L, narg)) {
|
||||
if (len)
|
||||
*len = (def ? strlen(def) : 0);
|
||||
return def;
|
||||
}
|
||||
else return luaL_checklstring(L, narg, len);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) {
|
||||
lua_Number d = lua_tonumber(L, narg);
|
||||
if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */
|
||||
tag_error(L, narg, LUA_TNUMBER);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) {
|
||||
return luaL_opt(L, luaL_checknumber, narg, def);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) {
|
||||
lua_Integer d = lua_tointeger(L, narg);
|
||||
if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */
|
||||
tag_error(L, narg, LUA_TNUMBER);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg,
|
||||
lua_Integer def) {
|
||||
return luaL_opt(L, luaL_checkinteger, narg, def);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
|
||||
if (!lua_getmetatable(L, obj)) /* no metatable? */
|
||||
return 0;
|
||||
lua_pushstring(L, event);
|
||||
lua_rawget(L, -2);
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 2); /* remove metatable and metafield */
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
lua_remove(L, -2); /* remove only metatable */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) {
|
||||
obj = abs_index(L, obj);
|
||||
if (!luaL_getmetafield(L, obj, event)) /* no metafield? */
|
||||
return 0;
|
||||
lua_pushvalue(L, obj);
|
||||
lua_call(L, 1, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
|
||||
const luaL_Reg *l) {
|
||||
luaI_openlib(L, libname, l, 0);
|
||||
}
|
||||
|
||||
|
||||
static int libsize (const luaL_Reg *l) {
|
||||
int size = 0;
|
||||
for (; l->name; l++) size++;
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaI_openlib (lua_State *L, const char *libname,
|
||||
const luaL_Reg *l, int nup) {
|
||||
if (libname) {
|
||||
int size = libsize(l);
|
||||
/* check whether lib already exists */
|
||||
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", size);
|
||||
lua_getfield(L, -1, libname); /* get _LOADED[libname] */
|
||||
if (!lua_istable(L, -1)) { /* not found? */
|
||||
lua_pop(L, 1); /* remove previous result */
|
||||
/* try global variable (and create one if it does not exist) */
|
||||
if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL)
|
||||
luaL_error(L, "name conflict for module " LUA_QS, libname);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */
|
||||
}
|
||||
lua_remove(L, -2); /* remove _LOADED table */
|
||||
lua_insert(L, -(nup+1)); /* move library table to below upvalues */
|
||||
}
|
||||
for (; l->name; l++) {
|
||||
int i;
|
||||
for (i=0; i<nup; i++) /* copy upvalues to the top */
|
||||
lua_pushvalue(L, -nup);
|
||||
lua_pushcclosure(L, l->func, nup);
|
||||
lua_setfield(L, -(nup+2), l->name);
|
||||
}
|
||||
lua_pop(L, nup); /* remove upvalues */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** getn-setn: size for arrays
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
#if defined(LUA_COMPAT_GETN)
|
||||
|
||||
static int checkint (lua_State *L, int topop) {
|
||||
int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1;
|
||||
lua_pop(L, topop);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
static void getsizes (lua_State *L) {
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, "LUA_SIZES");
|
||||
if (lua_isnil(L, -1)) { /* no `size' table? */
|
||||
lua_pop(L, 1); /* remove nil */
|
||||
lua_newtable(L); /* create it */
|
||||
lua_pushvalue(L, -1); /* `size' will be its own metatable */
|
||||
lua_setmetatable(L, -2);
|
||||
lua_pushliteral(L, "kv");
|
||||
lua_setfield(L, -2, "__mode"); /* metatable(N).__mode = "kv" */
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, "LUA_SIZES"); /* store in register */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_setn (lua_State *L, int t, int n) {
|
||||
t = abs_index(L, t);
|
||||
lua_pushliteral(L, "n");
|
||||
lua_rawget(L, t);
|
||||
if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */
|
||||
lua_pushliteral(L, "n"); /* use it */
|
||||
lua_pushinteger(L, n);
|
||||
lua_rawset(L, t);
|
||||
}
|
||||
else { /* use `sizes' */
|
||||
getsizes(L);
|
||||
lua_pushvalue(L, t);
|
||||
lua_pushinteger(L, n);
|
||||
lua_rawset(L, -3); /* sizes[t] = n */
|
||||
lua_pop(L, 1); /* remove `sizes' */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int luaL_getn (lua_State *L, int t) {
|
||||
int n;
|
||||
t = abs_index(L, t);
|
||||
lua_pushliteral(L, "n"); /* try t.n */
|
||||
lua_rawget(L, t);
|
||||
if ((n = checkint(L, 1)) >= 0) return n;
|
||||
getsizes(L); /* else try sizes[t] */
|
||||
lua_pushvalue(L, t);
|
||||
lua_rawget(L, -2);
|
||||
if ((n = checkint(L, 2)) >= 0) return n;
|
||||
return (int)lua_objlen(L, t);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
|
||||
LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p,
|
||||
const char *r) {
|
||||
const char *wild;
|
||||
size_t l = strlen(p);
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L, &b);
|
||||
while ((wild = strstr(s, p)) != NULL) {
|
||||
luaL_addlstring(&b, s, wild - s); /* push prefix */
|
||||
luaL_addstring(&b, r); /* push replacement in place of pattern */
|
||||
s = wild + l; /* continue after `p' */
|
||||
}
|
||||
luaL_addstring(&b, s); /* push last suffix */
|
||||
luaL_pushresult(&b);
|
||||
return lua_tostring(L, -1);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API const char *luaL_findtable (lua_State *L, int idx,
|
||||
const char *fname, int szhint) {
|
||||
const char *e;
|
||||
lua_pushvalue(L, idx);
|
||||
do {
|
||||
e = strchr(fname, '.');
|
||||
if (e == NULL) e = fname + strlen(fname);
|
||||
lua_pushlstring(L, fname, e - fname);
|
||||
lua_rawget(L, -2);
|
||||
if (lua_isnil(L, -1)) { /* no such field? */
|
||||
lua_pop(L, 1); /* remove this nil */
|
||||
lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
|
||||
lua_pushlstring(L, fname, e - fname);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, -4); /* set new table into field */
|
||||
}
|
||||
else if (!lua_istable(L, -1)) { /* field has a non-table value? */
|
||||
lua_pop(L, 2); /* remove table and value */
|
||||
return fname; /* return problematic part of the name */
|
||||
}
|
||||
lua_remove(L, -2); /* remove previous table */
|
||||
fname = e + 1;
|
||||
} while (*e == '.');
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Generic Buffer manipulation
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
|
||||
#define bufflen(B) ((B)->p - (B)->buffer)
|
||||
#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
|
||||
|
||||
#define LIMIT (LUA_MINSTACK/2)
|
||||
|
||||
|
||||
static int emptybuffer (luaL_Buffer *B) {
|
||||
size_t l = bufflen(B);
|
||||
if (l == 0) return 0; /* put nothing on stack */
|
||||
else {
|
||||
lua_pushlstring(B->L, B->buffer, l);
|
||||
B->p = B->buffer;
|
||||
B->lvl++;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void adjuststack (luaL_Buffer *B) {
|
||||
if (B->lvl > 1) {
|
||||
lua_State *L = B->L;
|
||||
int toget = 1; /* number of levels to concat */
|
||||
size_t toplen = lua_strlen(L, -1);
|
||||
do {
|
||||
size_t l = lua_strlen(L, -(toget+1));
|
||||
if (B->lvl - toget + 1 >= LIMIT || toplen > l) {
|
||||
toplen += l;
|
||||
toget++;
|
||||
}
|
||||
else break;
|
||||
} while (toget < B->lvl);
|
||||
lua_concat(L, toget);
|
||||
B->lvl = B->lvl - toget + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) {
|
||||
if (emptybuffer(B))
|
||||
adjuststack(B);
|
||||
return B->buffer;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
|
||||
while (l--)
|
||||
luaL_addchar(B, *s++);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
|
||||
luaL_addlstring(B, s, strlen(s));
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
|
||||
emptybuffer(B);
|
||||
lua_concat(B->L, B->lvl);
|
||||
B->lvl = 1;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_addvalue (luaL_Buffer *B) {
|
||||
lua_State *L = B->L;
|
||||
size_t vl;
|
||||
const char *s = lua_tolstring(L, -1, &vl);
|
||||
if (vl <= bufffree(B)) { /* fit into buffer? */
|
||||
memcpy(B->p, s, vl); /* put it there */
|
||||
B->p += vl;
|
||||
lua_pop(L, 1); /* remove from stack */
|
||||
}
|
||||
else {
|
||||
if (emptybuffer(B))
|
||||
lua_insert(L, -2); /* put buffer before new value */
|
||||
B->lvl++; /* add new value into B stack */
|
||||
adjuststack(B);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
|
||||
B->L = L;
|
||||
B->p = B->buffer;
|
||||
B->lvl = 0;
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
LUALIB_API int luaL_ref (lua_State *L, int t) {
|
||||
int ref;
|
||||
t = abs_index(L, t);
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1); /* remove from stack */
|
||||
return LUA_REFNIL; /* `nil' has a unique fixed reference */
|
||||
}
|
||||
lua_rawgeti(L, t, FREELIST_REF); /* get first free element */
|
||||
ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */
|
||||
lua_pop(L, 1); /* remove it from stack */
|
||||
if (ref != 0) { /* any free element? */
|
||||
lua_rawgeti(L, t, ref); /* remove it from list */
|
||||
lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */
|
||||
}
|
||||
else { /* no free elements */
|
||||
ref = (int)lua_objlen(L, t);
|
||||
ref++; /* create new reference */
|
||||
}
|
||||
lua_rawseti(L, t, ref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
|
||||
if (ref >= 0) {
|
||||
t = abs_index(L, t);
|
||||
lua_rawgeti(L, t, FREELIST_REF);
|
||||
lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */
|
||||
lua_pushinteger(L, ref);
|
||||
lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Load functions
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
typedef struct LoadF {
|
||||
int extraline;
|
||||
FILE *f;
|
||||
char buff[LUAL_BUFFERSIZE];
|
||||
} LoadF;
|
||||
|
||||
|
||||
static const char *getF (lua_State *L, void *ud, size_t *size) {
|
||||
LoadF *lf = (LoadF *)ud;
|
||||
(void)L;
|
||||
if (lf->extraline) {
|
||||
lf->extraline = 0;
|
||||
*size = 1;
|
||||
return "\n";
|
||||
}
|
||||
if (feof(lf->f)) return NULL;
|
||||
*size = fread(lf->buff, 1, LUAL_BUFFERSIZE, lf->f);
|
||||
return (*size > 0) ? lf->buff : NULL;
|
||||
}
|
||||
|
||||
|
||||
static int errfile (lua_State *L, const char *what, int fnameindex) {
|
||||
const char *serr = strerror(errno);
|
||||
const char *filename = lua_tostring(L, fnameindex) + 1;
|
||||
lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
|
||||
lua_remove(L, fnameindex);
|
||||
return LUA_ERRFILE;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {
|
||||
LoadF lf;
|
||||
int status, readstatus;
|
||||
int c;
|
||||
int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */
|
||||
lf.extraline = 0;
|
||||
if (filename == NULL) {
|
||||
lua_pushliteral(L, "=stdin");
|
||||
lf.f = stdin;
|
||||
}
|
||||
else {
|
||||
lua_pushfstring(L, "@%s", filename);
|
||||
lf.f = fopen(filename, "r");
|
||||
if (lf.f == NULL) return errfile(L, "open", fnameindex);
|
||||
}
|
||||
c = getc(lf.f);
|
||||
if (c == '#') { /* Unix exec. file? */
|
||||
lf.extraline = 1;
|
||||
while ((c = getc(lf.f)) != EOF && c != '\n') ; /* skip first line */
|
||||
if (c == '\n') c = getc(lf.f);
|
||||
}
|
||||
if (c == LUA_SIGNATURE[0] && lf.f != stdin) { /* binary file? */
|
||||
fclose(lf.f);
|
||||
lf.f = fopen(filename, "rb"); /* reopen in binary mode */
|
||||
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
|
||||
/* skip eventual `#!...' */
|
||||
while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ;
|
||||
lf.extraline = 0;
|
||||
}
|
||||
ungetc(c, lf.f);
|
||||
status = lua_load(L, getF, &lf, lua_tostring(L, -1));
|
||||
readstatus = ferror(lf.f);
|
||||
if (lf.f != stdin) fclose(lf.f); /* close file (even in case of errors) */
|
||||
if (readstatus) {
|
||||
lua_settop(L, fnameindex); /* ignore results from `lua_load' */
|
||||
return errfile(L, "read", fnameindex);
|
||||
}
|
||||
lua_remove(L, fnameindex);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
typedef struct LoadS {
|
||||
const char *s;
|
||||
size_t size;
|
||||
} LoadS;
|
||||
|
||||
|
||||
static const char *getS (lua_State *L, void *ud, size_t *size) {
|
||||
LoadS *ls = (LoadS *)ud;
|
||||
(void)L;
|
||||
if (ls->size == 0) return NULL;
|
||||
*size = ls->size;
|
||||
ls->size = 0;
|
||||
return ls->s;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size,
|
||||
const char *name) {
|
||||
LoadS ls;
|
||||
ls.s = buff;
|
||||
ls.size = size;
|
||||
return lua_load(L, getS, &ls, name);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) {
|
||||
return luaL_loadbuffer(L, s, strlen(s), s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
|
||||
(void)ud;
|
||||
(void)osize;
|
||||
if (nsize == 0) {
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return realloc(ptr, nsize);
|
||||
}
|
||||
|
||||
|
||||
static int panic (lua_State *L) {
|
||||
(void)L; /* to avoid warnings */
|
||||
fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n",
|
||||
lua_tostring(L, -1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API lua_State *luaL_newstate (void) {
|
||||
lua_State *L = lua_newstate(l_alloc, NULL);
|
||||
if (L) lua_atpanic(L, &panic);
|
||||
return L;
|
||||
}
|
||||
|
172
src/lua/lauxlib.h
Normal file
172
src/lua/lauxlib.h
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
** $Id: lauxlib.h,v 1.87 2005/12/29 15:32:11 roberto Exp $
|
||||
** Auxiliary functions for building Lua libraries
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef lauxlib_h
|
||||
#define lauxlib_h
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
|
||||
#if defined(LUA_COMPAT_GETN)
|
||||
LUALIB_API int (luaL_getn) (lua_State *L, int t);
|
||||
LUALIB_API void (luaL_setn) (lua_State *L, int t, int n);
|
||||
#else
|
||||
#define luaL_getn(L,i) ((int)lua_objlen(L, i))
|
||||
#define luaL_setn(L,i,j) ((void)0) /* no op! */
|
||||
#endif
|
||||
|
||||
#if defined(LUA_COMPAT_OPENLIB)
|
||||
#define luaI_openlib luaL_openlib
|
||||
#endif
|
||||
|
||||
|
||||
/* extra error code for `luaL_load' */
|
||||
#define LUA_ERRFILE (LUA_ERRERR+1)
|
||||
|
||||
|
||||
typedef struct luaL_Reg {
|
||||
const char *name;
|
||||
lua_CFunction func;
|
||||
} luaL_Reg;
|
||||
|
||||
|
||||
|
||||
LUALIB_API void (luaI_openlib) (lua_State *L, const char *libname,
|
||||
const luaL_Reg *l, int nup);
|
||||
LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
|
||||
const luaL_Reg *l);
|
||||
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
|
||||
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
|
||||
LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname);
|
||||
LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
|
||||
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
|
||||
size_t *l);
|
||||
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
|
||||
const char *def, size_t *l);
|
||||
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
|
||||
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);
|
||||
|
||||
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
|
||||
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
|
||||
lua_Integer def);
|
||||
|
||||
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
|
||||
LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
|
||||
LUALIB_API void (luaL_checkany) (lua_State *L, int narg);
|
||||
|
||||
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
|
||||
LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
|
||||
|
||||
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
|
||||
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
|
||||
|
||||
LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
|
||||
const char *const lst[]);
|
||||
|
||||
LUALIB_API int (luaL_ref) (lua_State *L, int t);
|
||||
LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
|
||||
|
||||
LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename);
|
||||
LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz,
|
||||
const char *name);
|
||||
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
|
||||
|
||||
LUALIB_API lua_State *(luaL_newstate) (void);
|
||||
|
||||
|
||||
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
|
||||
const char *r);
|
||||
|
||||
LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx,
|
||||
const char *fname, int szhint);
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** ===============================================================
|
||||
** some useful macros
|
||||
** ===============================================================
|
||||
*/
|
||||
|
||||
#define luaL_argcheck(L, cond,numarg,extramsg) \
|
||||
((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
|
||||
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
|
||||
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
|
||||
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
|
||||
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
|
||||
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
|
||||
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
|
||||
|
||||
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
|
||||
|
||||
#define luaL_dofile(L, fn) (luaL_loadfile(L, fn) || lua_pcall(L, 0, 0, 0))
|
||||
|
||||
#define luaL_dostring(L, s) (luaL_loadstring(L, s) || lua_pcall(L, 0, 0, 0))
|
||||
|
||||
#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
|
||||
|
||||
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Generic Buffer manipulation
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
|
||||
|
||||
typedef struct luaL_Buffer {
|
||||
char *p; /* current position in buffer */
|
||||
int lvl; /* number of strings in the stack (level) */
|
||||
lua_State *L;
|
||||
char buffer[LUAL_BUFFERSIZE];
|
||||
} luaL_Buffer;
|
||||
|
||||
#define luaL_addchar(B,c) \
|
||||
((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
|
||||
(*(B)->p++ = (char)(c)))
|
||||
|
||||
/* compatibility only */
|
||||
#define luaL_putchar(B,c) luaL_addchar(B,c)
|
||||
|
||||
#define luaL_addsize(B,n) ((B)->p += (n))
|
||||
|
||||
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
|
||||
LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B);
|
||||
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
|
||||
LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
|
||||
LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
|
||||
LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
|
||||
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
/* compatibility with ref system */
|
||||
|
||||
/* pre-defined references */
|
||||
#define LUA_NOREF (-2)
|
||||
#define LUA_REFNIL (-1)
|
||||
|
||||
#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \
|
||||
(lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0))
|
||||
|
||||
#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref))
|
||||
|
||||
#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref))
|
||||
|
||||
|
||||
#define luaL_reg luaL_Reg
|
||||
|
||||
#endif
|
||||
|
||||
|
643
src/lua/lbaselib.c
Normal file
643
src/lua/lbaselib.c
Normal file
@ -0,0 +1,643 @@
|
||||
/*
|
||||
** $Id: lbaselib.c,v 1.189 2006/01/18 11:49:12 roberto Exp $
|
||||
** Basic library
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define lbaselib_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** If your system does not support `stdout', you can just remove this function.
|
||||
** If you need, you can define your own `print' function, following this
|
||||
** model but changing `fputs' to put the strings at a proper place
|
||||
** (a console window or a log file, for instance).
|
||||
*/
|
||||
static int luaB_print (lua_State *L) {
|
||||
int n = lua_gettop(L); /* number of arguments */
|
||||
int i;
|
||||
lua_getglobal(L, "tostring");
|
||||
for (i=1; i<=n; i++) {
|
||||
const char *s;
|
||||
lua_pushvalue(L, -1); /* function to be called */
|
||||
lua_pushvalue(L, i); /* value to print */
|
||||
lua_call(L, 1, 1);
|
||||
s = lua_tostring(L, -1); /* get result */
|
||||
if (s == NULL)
|
||||
return luaL_error(L, LUA_QL("tostring") " must return a string to "
|
||||
LUA_QL("print"));
|
||||
if (i>1) fputs("\t", stdout);
|
||||
fputs(s, stdout);
|
||||
lua_pop(L, 1); /* pop result */
|
||||
}
|
||||
fputs("\n", stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_tonumber (lua_State *L) {
|
||||
int base = luaL_optint(L, 2, 10);
|
||||
if (base == 10) { /* standard conversion */
|
||||
luaL_checkany(L, 1);
|
||||
if (lua_isnumber(L, 1)) {
|
||||
lua_pushnumber(L, lua_tonumber(L, 1));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const char *s1 = luaL_checkstring(L, 1);
|
||||
char *s2;
|
||||
unsigned long n;
|
||||
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
|
||||
n = strtoul(s1, &s2, base);
|
||||
if (s1 != s2) { /* at least one valid digit? */
|
||||
while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */
|
||||
if (*s2 == '\0') { /* no invalid trailing characters? */
|
||||
lua_pushnumber(L, (lua_Number)n);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
lua_pushnil(L); /* else not a number */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_error (lua_State *L) {
|
||||
int level = luaL_optint(L, 2, 1);
|
||||
lua_settop(L, 1);
|
||||
if (lua_isstring(L, 1) && level > 0) { /* add extra information? */
|
||||
luaL_where(L, level);
|
||||
lua_pushvalue(L, 1);
|
||||
lua_concat(L, 2);
|
||||
}
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
|
||||
static int luaB_getmetatable (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
if (!lua_getmetatable(L, 1)) {
|
||||
lua_pushnil(L);
|
||||
return 1; /* no metatable */
|
||||
}
|
||||
luaL_getmetafield(L, 1, "__metatable");
|
||||
return 1; /* returns either __metatable field (if present) or metatable */
|
||||
}
|
||||
|
||||
|
||||
static int luaB_setmetatable (lua_State *L) {
|
||||
int t = lua_type(L, 2);
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
|
||||
"nil or table expected");
|
||||
if (luaL_getmetafield(L, 1, "__metatable"))
|
||||
luaL_error(L, "cannot change a protected metatable");
|
||||
lua_settop(L, 2);
|
||||
lua_setmetatable(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void getfunc (lua_State *L) {
|
||||
if (lua_isfunction(L, 1)) lua_pushvalue(L, 1);
|
||||
else {
|
||||
lua_Debug ar;
|
||||
int level = luaL_optint(L, 1, 1);
|
||||
luaL_argcheck(L, level >= 0, 1, "level must be non-negative");
|
||||
if (lua_getstack(L, level, &ar) == 0)
|
||||
luaL_argerror(L, 1, "invalid level");
|
||||
lua_getinfo(L, "f", &ar);
|
||||
if (lua_isnil(L, -1))
|
||||
luaL_error(L, "no function environment for tail call at level %d",
|
||||
level);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_getfenv (lua_State *L) {
|
||||
getfunc(L);
|
||||
if (lua_iscfunction(L, -1)) /* is a C function? */
|
||||
lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */
|
||||
else
|
||||
lua_getfenv(L, -1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_setfenv (lua_State *L) {
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
getfunc(L);
|
||||
lua_pushvalue(L, 2);
|
||||
if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) {
|
||||
/* change environment of current thread */
|
||||
lua_pushthread(L);
|
||||
lua_insert(L, -2);
|
||||
lua_setfenv(L, -2);
|
||||
return 0;
|
||||
}
|
||||
else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0)
|
||||
luaL_error(L,
|
||||
LUA_QL("setfenv") " cannot change environment of given object");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_rawequal (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
luaL_checkany(L, 2);
|
||||
lua_pushboolean(L, lua_rawequal(L, 1, 2));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_rawget (lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
luaL_checkany(L, 2);
|
||||
lua_settop(L, 2);
|
||||
lua_rawget(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaB_rawset (lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
luaL_checkany(L, 2);
|
||||
luaL_checkany(L, 3);
|
||||
lua_settop(L, 3);
|
||||
lua_rawset(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_gcinfo (lua_State *L) {
|
||||
lua_pushinteger(L, lua_getgccount(L));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_collectgarbage (lua_State *L) {
|
||||
static const char *const opts[] = {"stop", "restart", "collect",
|
||||
"count", "step", "setpause", "setstepmul", NULL};
|
||||
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
|
||||
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL};
|
||||
int o = luaL_checkoption(L, 1, "collect", opts);
|
||||
int ex = luaL_optint(L, 2, 0);
|
||||
int res = lua_gc(L, optsnum[o], ex);
|
||||
switch (optsnum[o]) {
|
||||
case LUA_GCCOUNT: {
|
||||
int b = lua_gc(L, LUA_GCCOUNTB, 0);
|
||||
lua_pushnumber(L, res + ((lua_Number)b/1024));
|
||||
return 1;
|
||||
}
|
||||
case LUA_GCSTEP: {
|
||||
lua_pushboolean(L, res);
|
||||
return 1;
|
||||
}
|
||||
default: {
|
||||
lua_pushnumber(L, res);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_type (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
lua_pushstring(L, luaL_typename(L, 1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_next (lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
lua_settop(L, 2); /* create a 2nd argument if there isn't one */
|
||||
if (lua_next(L, 1))
|
||||
return 2;
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_pairs (lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
|
||||
lua_pushvalue(L, 1); /* state, */
|
||||
lua_pushnil(L); /* and initial value */
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
static int ipairsaux (lua_State *L) {
|
||||
int i = luaL_checkint(L, 2);
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
i++; /* next value */
|
||||
lua_pushinteger(L, i);
|
||||
lua_rawgeti(L, 1, i);
|
||||
return (lua_isnil(L, -1)) ? 0 : 2;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_ipairs (lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
|
||||
lua_pushvalue(L, 1); /* state, */
|
||||
lua_pushinteger(L, 0); /* and initial value */
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
static int load_aux (lua_State *L, int status) {
|
||||
if (status == 0) /* OK? */
|
||||
return 1;
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
lua_insert(L, -2); /* put before error message */
|
||||
return 2; /* return nil plus error message */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_loadstring (lua_State *L) {
|
||||
size_t l;
|
||||
const char *s = luaL_checklstring(L, 1, &l);
|
||||
const char *chunkname = luaL_optstring(L, 2, s);
|
||||
return load_aux(L, luaL_loadbuffer(L, s, l, chunkname));
|
||||
}
|
||||
|
||||
|
||||
static int luaB_loadfile (lua_State *L) {
|
||||
const char *fname = luaL_optstring(L, 1, NULL);
|
||||
return load_aux(L, luaL_loadfile(L, fname));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Reader for generic `load' function: `lua_load' uses the
|
||||
** stack for internal stuff, so the reader cannot change the
|
||||
** stack top. Instead, it keeps its resulting string in a
|
||||
** reserved slot inside the stack.
|
||||
*/
|
||||
static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
|
||||
(void)ud; /* to avoid warnings */
|
||||
luaL_checkstack(L, 2, "too many nested functions");
|
||||
lua_pushvalue(L, 1); /* get function */
|
||||
lua_call(L, 0, 1); /* call it */
|
||||
if (lua_isnil(L, -1)) {
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
else if (lua_isstring(L, -1)) {
|
||||
lua_replace(L, 3); /* save string in a reserved stack slot */
|
||||
return lua_tolstring(L, 3, size);
|
||||
}
|
||||
else luaL_error(L, "reader function must return a string");
|
||||
return NULL; /* to avoid warnings */
|
||||
}
|
||||
|
||||
|
||||
static int luaB_load (lua_State *L) {
|
||||
int status;
|
||||
const char *cname = luaL_optstring(L, 2, "=(load)");
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
lua_settop(L, 3); /* function, eventual name, plus one reserved slot */
|
||||
status = lua_load(L, generic_reader, NULL, cname);
|
||||
return load_aux(L, status);
|
||||
}
|
||||
|
||||
|
||||
static int luaB_dofile (lua_State *L) {
|
||||
const char *fname = luaL_optstring(L, 1, NULL);
|
||||
int n = lua_gettop(L);
|
||||
if (luaL_loadfile(L, fname) != 0) lua_error(L);
|
||||
lua_call(L, 0, LUA_MULTRET);
|
||||
return lua_gettop(L) - n;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_assert (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
if (!lua_toboolean(L, 1))
|
||||
return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!"));
|
||||
return lua_gettop(L);
|
||||
}
|
||||
|
||||
|
||||
static int luaB_unpack (lua_State *L) {
|
||||
int i, e, n;
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
i = luaL_optint(L, 2, 1);
|
||||
e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1));
|
||||
n = e - i + 1; /* number of elements */
|
||||
if (n <= 0) return 0; /* empty range */
|
||||
luaL_checkstack(L, n, "table too big to unpack");
|
||||
for (; i<=e; i++) /* push arg[i...e] */
|
||||
lua_rawgeti(L, 1, i);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_select (lua_State *L) {
|
||||
int n = lua_gettop(L);
|
||||
if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') {
|
||||
lua_pushinteger(L, n-1);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
int i = luaL_checkint(L, 1);
|
||||
if (i < 0) i = n + i;
|
||||
else if (i > n) i = n;
|
||||
luaL_argcheck(L, 1 <= i, 1, "index out of range");
|
||||
return n - i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_pcall (lua_State *L) {
|
||||
int status;
|
||||
luaL_checkany(L, 1);
|
||||
status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0);
|
||||
lua_pushboolean(L, (status == 0));
|
||||
lua_insert(L, 1);
|
||||
return lua_gettop(L); /* return status + all results */
|
||||
}
|
||||
|
||||
|
||||
static int luaB_xpcall (lua_State *L) {
|
||||
int status;
|
||||
luaL_checkany(L, 2);
|
||||
lua_settop(L, 2);
|
||||
lua_insert(L, 1); /* put error function under function to be called */
|
||||
status = lua_pcall(L, 0, LUA_MULTRET, 1);
|
||||
lua_pushboolean(L, (status == 0));
|
||||
lua_replace(L, 1);
|
||||
return lua_gettop(L); /* return status + all results */
|
||||
}
|
||||
|
||||
|
||||
static int luaB_tostring (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */
|
||||
return 1; /* use its value */
|
||||
switch (lua_type(L, 1)) {
|
||||
case LUA_TNUMBER:
|
||||
lua_pushstring(L, lua_tostring(L, 1));
|
||||
break;
|
||||
case LUA_TSTRING:
|
||||
lua_pushvalue(L, 1);
|
||||
break;
|
||||
case LUA_TBOOLEAN:
|
||||
lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false"));
|
||||
break;
|
||||
case LUA_TNIL:
|
||||
lua_pushliteral(L, "nil");
|
||||
break;
|
||||
default:
|
||||
lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1));
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_newproxy (lua_State *L) {
|
||||
lua_settop(L, 1);
|
||||
lua_newuserdata(L, 0); /* create proxy */
|
||||
if (lua_toboolean(L, 1) == 0)
|
||||
return 1; /* no metatable */
|
||||
else if (lua_isboolean(L, 1)) {
|
||||
lua_newtable(L); /* create a new metatable `m' ... */
|
||||
lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */
|
||||
lua_pushboolean(L, 1);
|
||||
lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */
|
||||
}
|
||||
else {
|
||||
int validproxy = 0; /* to check if weaktable[metatable(u)] == true */
|
||||
if (lua_getmetatable(L, 1)) {
|
||||
lua_rawget(L, lua_upvalueindex(1));
|
||||
validproxy = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1); /* remove value */
|
||||
}
|
||||
luaL_argcheck(L, validproxy, 1, "boolean or proxy expected");
|
||||
lua_getmetatable(L, 1); /* metatable is valid; get it */
|
||||
}
|
||||
lua_setmetatable(L, 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static const luaL_Reg base_funcs[] = {
|
||||
{"assert", luaB_assert},
|
||||
{"collectgarbage", luaB_collectgarbage},
|
||||
{"dofile", luaB_dofile},
|
||||
{"error", luaB_error},
|
||||
{"gcinfo", luaB_gcinfo},
|
||||
{"getfenv", luaB_getfenv},
|
||||
{"getmetatable", luaB_getmetatable},
|
||||
{"loadfile", luaB_loadfile},
|
||||
{"load", luaB_load},
|
||||
{"loadstring", luaB_loadstring},
|
||||
{"next", luaB_next},
|
||||
{"pcall", luaB_pcall},
|
||||
{"print", luaB_print},
|
||||
{"rawequal", luaB_rawequal},
|
||||
{"rawget", luaB_rawget},
|
||||
{"rawset", luaB_rawset},
|
||||
{"select", luaB_select},
|
||||
{"setfenv", luaB_setfenv},
|
||||
{"setmetatable", luaB_setmetatable},
|
||||
{"tonumber", luaB_tonumber},
|
||||
{"tostring", luaB_tostring},
|
||||
{"type", luaB_type},
|
||||
{"unpack", luaB_unpack},
|
||||
{"xpcall", luaB_xpcall},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Coroutine library
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
static int auxresume (lua_State *L, lua_State *co, int narg) {
|
||||
int status;
|
||||
if (!lua_checkstack(co, narg))
|
||||
luaL_error(L, "too many arguments to resume");
|
||||
if (lua_status(co) == 0 && lua_gettop(co) == 0) {
|
||||
lua_pushliteral(L, "cannot resume dead coroutine");
|
||||
return -1; /* error flag */
|
||||
}
|
||||
lua_xmove(L, co, narg);
|
||||
status = lua_resume(co, narg);
|
||||
if (status == 0 || status == LUA_YIELD) {
|
||||
int nres = lua_gettop(co);
|
||||
if (!lua_checkstack(L, nres))
|
||||
luaL_error(L, "too many results to resume");
|
||||
lua_xmove(co, L, nres); /* move yielded values */
|
||||
return nres;
|
||||
}
|
||||
else {
|
||||
lua_xmove(co, L, 1); /* move error message */
|
||||
return -1; /* error flag */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_coresume (lua_State *L) {
|
||||
lua_State *co = lua_tothread(L, 1);
|
||||
int r;
|
||||
luaL_argcheck(L, co, 1, "coroutine expected");
|
||||
r = auxresume(L, co, lua_gettop(L) - 1);
|
||||
if (r < 0) {
|
||||
lua_pushboolean(L, 0);
|
||||
lua_insert(L, -2);
|
||||
return 2; /* return false + error message */
|
||||
}
|
||||
else {
|
||||
lua_pushboolean(L, 1);
|
||||
lua_insert(L, -(r + 1));
|
||||
return r + 1; /* return true + `resume' returns */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_auxwrap (lua_State *L) {
|
||||
lua_State *co = lua_tothread(L, lua_upvalueindex(1));
|
||||
int r = auxresume(L, co, lua_gettop(L));
|
||||
if (r < 0) {
|
||||
if (lua_isstring(L, -1)) { /* error object is a string? */
|
||||
luaL_where(L, 1); /* add extra info */
|
||||
lua_insert(L, -2);
|
||||
lua_concat(L, 2);
|
||||
}
|
||||
lua_error(L); /* propagate error */
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_cocreate (lua_State *L) {
|
||||
lua_State *NL = lua_newthread(L);
|
||||
luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
|
||||
"Lua function expected");
|
||||
lua_pushvalue(L, 1); /* move function to top */
|
||||
lua_xmove(L, NL, 1); /* move function from L to NL */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_cowrap (lua_State *L) {
|
||||
luaB_cocreate(L);
|
||||
lua_pushcclosure(L, luaB_auxwrap, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_yield (lua_State *L) {
|
||||
return lua_yield(L, lua_gettop(L));
|
||||
}
|
||||
|
||||
|
||||
static int luaB_costatus (lua_State *L) {
|
||||
lua_State *co = lua_tothread(L, 1);
|
||||
luaL_argcheck(L, co, 1, "coroutine expected");
|
||||
if (L == co) lua_pushliteral(L, "running");
|
||||
else {
|
||||
switch (lua_status(co)) {
|
||||
case LUA_YIELD:
|
||||
lua_pushliteral(L, "suspended");
|
||||
break;
|
||||
case 0: {
|
||||
lua_Debug ar;
|
||||
if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */
|
||||
lua_pushliteral(L, "normal"); /* it is running */
|
||||
else if (lua_gettop(co) == 0)
|
||||
lua_pushliteral(L, "dead");
|
||||
else
|
||||
lua_pushliteral(L, "suspended"); /* initial state */
|
||||
break;
|
||||
}
|
||||
default: /* some error occured */
|
||||
lua_pushliteral(L, "dead");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_corunning (lua_State *L) {
|
||||
if (lua_pushthread(L))
|
||||
return 0; /* main thread is not a coroutine */
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static const luaL_Reg co_funcs[] = {
|
||||
{"create", luaB_cocreate},
|
||||
{"resume", luaB_coresume},
|
||||
{"running", luaB_corunning},
|
||||
{"status", luaB_costatus},
|
||||
{"wrap", luaB_cowrap},
|
||||
{"yield", luaB_yield},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
static void auxopen (lua_State *L, const char *name,
|
||||
lua_CFunction f, lua_CFunction u) {
|
||||
lua_pushcfunction(L, u);
|
||||
lua_pushcclosure(L, f, 1);
|
||||
lua_setfield(L, -2, name);
|
||||
}
|
||||
|
||||
|
||||
static void base_open (lua_State *L) {
|
||||
/* set global _G */
|
||||
lua_pushvalue(L, LUA_GLOBALSINDEX);
|
||||
lua_setglobal(L, "_G");
|
||||
/* open lib into global table */
|
||||
luaL_register(L, "_G", base_funcs);
|
||||
lua_pushliteral(L, LUA_VERSION);
|
||||
lua_setglobal(L, "_VERSION"); /* set global _VERSION */
|
||||
/* `ipairs' and `pairs' need auxliliary functions as upvalues */
|
||||
auxopen(L, "ipairs", luaB_ipairs, ipairsaux);
|
||||
auxopen(L, "pairs", luaB_pairs, luaB_next);
|
||||
/* `newproxy' needs a weaktable as upvalue */
|
||||
lua_createtable(L, 0, 1); /* new table `w' */
|
||||
lua_pushvalue(L, -1); /* `w' will be its own metatable */
|
||||
lua_setmetatable(L, -2);
|
||||
lua_pushliteral(L, "kv");
|
||||
lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */
|
||||
lua_pushcclosure(L, luaB_newproxy, 1);
|
||||
lua_setglobal(L, "newproxy"); /* set global `newproxy' */
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int luaopen_base (lua_State *L) {
|
||||
base_open(L);
|
||||
luaL_register(L, LUA_COLIBNAME, co_funcs);
|
||||
return 2;
|
||||
}
|
||||
|
825
src/lua/lcode.c
Normal file
825
src/lua/lcode.c
Normal file
@ -0,0 +1,825 @@
|
||||
/*
|
||||
** $Id: lcode.c,v 2.24 2005/12/22 16:19:56 roberto Exp $
|
||||
** Code generator for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define lcode_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lcode.h"
|
||||
#include "ldebug.h"
|
||||
#include "ldo.h"
|
||||
#include "lgc.h"
|
||||
#include "llex.h"
|
||||
#include "lmem.h"
|
||||
#include "lobject.h"
|
||||
#include "lopcodes.h"
|
||||
#include "lparser.h"
|
||||
#include "ltable.h"
|
||||
|
||||
|
||||
#define hasjumps(e) ((e)->t != (e)->f)
|
||||
|
||||
|
||||
static int isnumeral(expdesc *e) {
|
||||
return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
|
||||
}
|
||||
|
||||
|
||||
void luaK_nil (FuncState *fs, int from, int n) {
|
||||
Instruction *previous;
|
||||
if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
|
||||
if (fs->pc == 0) /* function start? */
|
||||
return; /* positions are already clean */
|
||||
if (GET_OPCODE(*(previous = &fs->f->code[fs->pc-1])) == OP_LOADNIL) {
|
||||
int pfrom = GETARG_A(*previous);
|
||||
int pto = GETARG_B(*previous);
|
||||
if (pfrom <= from && from <= pto+1) { /* can connect both? */
|
||||
if (from+n-1 > pto)
|
||||
SETARG_B(*previous, from+n-1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */
|
||||
}
|
||||
|
||||
|
||||
int luaK_jump (FuncState *fs) {
|
||||
int jpc = fs->jpc; /* save list of jumps to here */
|
||||
int j;
|
||||
fs->jpc = NO_JUMP;
|
||||
j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
|
||||
luaK_concat(fs, &j, jpc); /* keep them on hold */
|
||||
return j;
|
||||
}
|
||||
|
||||
|
||||
void luaK_ret (FuncState *fs, int first, int nret) {
|
||||
luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
|
||||
}
|
||||
|
||||
|
||||
static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
|
||||
luaK_codeABC(fs, op, A, B, C);
|
||||
return luaK_jump(fs);
|
||||
}
|
||||
|
||||
|
||||
static void fixjump (FuncState *fs, int pc, int dest) {
|
||||
Instruction *jmp = &fs->f->code[pc];
|
||||
int offset = dest-(pc+1);
|
||||
lua_assert(dest != NO_JUMP);
|
||||
if (abs(offset) > MAXARG_sBx)
|
||||
luaX_syntaxerror(fs->ls, "control structure too long");
|
||||
SETARG_sBx(*jmp, offset);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** returns current `pc' and marks it as a jump target (to avoid wrong
|
||||
** optimizations with consecutive instructions not in the same basic block).
|
||||
*/
|
||||
int luaK_getlabel (FuncState *fs) {
|
||||
fs->lasttarget = fs->pc;
|
||||
return fs->pc;
|
||||
}
|
||||
|
||||
|
||||
static int getjump (FuncState *fs, int pc) {
|
||||
int offset = GETARG_sBx(fs->f->code[pc]);
|
||||
if (offset == NO_JUMP) /* point to itself represents end of list */
|
||||
return NO_JUMP; /* end of list */
|
||||
else
|
||||
return (pc+1)+offset; /* turn offset into absolute position */
|
||||
}
|
||||
|
||||
|
||||
static Instruction *getjumpcontrol (FuncState *fs, int pc) {
|
||||
Instruction *pi = &fs->f->code[pc];
|
||||
if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
|
||||
return pi-1;
|
||||
else
|
||||
return pi;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** check whether list has any jump that do not produce a value
|
||||
** (or produce an inverted value)
|
||||
*/
|
||||
static int need_value (FuncState *fs, int list) {
|
||||
for (; list != NO_JUMP; list = getjump(fs, list)) {
|
||||
Instruction i = *getjumpcontrol(fs, list);
|
||||
if (GET_OPCODE(i) != OP_TESTSET) return 1;
|
||||
}
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
|
||||
static int patchtestreg (FuncState *fs, int node, int reg) {
|
||||
Instruction *i = getjumpcontrol(fs, node);
|
||||
if (GET_OPCODE(*i) != OP_TESTSET)
|
||||
return 0; /* cannot patch other instructions */
|
||||
if (reg != NO_REG && reg != GETARG_B(*i))
|
||||
SETARG_A(*i, reg);
|
||||
else /* no register to put value or register already has the value */
|
||||
*i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void removevalues (FuncState *fs, int list) {
|
||||
for (; list != NO_JUMP; list = getjump(fs, list))
|
||||
patchtestreg(fs, list, NO_REG);
|
||||
}
|
||||
|
||||
|
||||
static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
|
||||
int dtarget) {
|
||||
while (list != NO_JUMP) {
|
||||
int next = getjump(fs, list);
|
||||
if (patchtestreg(fs, list, reg))
|
||||
fixjump(fs, list, vtarget);
|
||||
else
|
||||
fixjump(fs, list, dtarget); /* jump to default target */
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void dischargejpc (FuncState *fs) {
|
||||
patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
|
||||
fs->jpc = NO_JUMP;
|
||||
}
|
||||
|
||||
|
||||
void luaK_patchlist (FuncState *fs, int list, int target) {
|
||||
if (target == fs->pc)
|
||||
luaK_patchtohere(fs, list);
|
||||
else {
|
||||
lua_assert(target < fs->pc);
|
||||
patchlistaux(fs, list, target, NO_REG, target);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_patchtohere (FuncState *fs, int list) {
|
||||
luaK_getlabel(fs);
|
||||
luaK_concat(fs, &fs->jpc, list);
|
||||
}
|
||||
|
||||
|
||||
void luaK_concat (FuncState *fs, int *l1, int l2) {
|
||||
if (l2 == NO_JUMP) return;
|
||||
else if (*l1 == NO_JUMP)
|
||||
*l1 = l2;
|
||||
else {
|
||||
int list = *l1;
|
||||
int next;
|
||||
while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */
|
||||
list = next;
|
||||
fixjump(fs, list, l2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_checkstack (FuncState *fs, int n) {
|
||||
int newstack = fs->freereg + n;
|
||||
if (newstack > fs->f->maxstacksize) {
|
||||
if (newstack >= MAXSTACK)
|
||||
luaX_syntaxerror(fs->ls, "function or expression too complex");
|
||||
fs->f->maxstacksize = cast_byte(newstack);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_reserveregs (FuncState *fs, int n) {
|
||||
luaK_checkstack(fs, n);
|
||||
fs->freereg += n;
|
||||
}
|
||||
|
||||
|
||||
static void freereg (FuncState *fs, int reg) {
|
||||
if (!ISK(reg) && reg >= fs->nactvar) {
|
||||
fs->freereg--;
|
||||
lua_assert(reg == fs->freereg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void freeexp (FuncState *fs, expdesc *e) {
|
||||
if (e->k == VNONRELOC)
|
||||
freereg(fs, e->u.s.info);
|
||||
}
|
||||
|
||||
|
||||
static int addk (FuncState *fs, TValue *k, TValue *v) {
|
||||
lua_State *L = fs->L;
|
||||
TValue *idx = luaH_set(L, fs->h, k);
|
||||
Proto *f = fs->f;
|
||||
int oldsize = f->sizek;
|
||||
if (ttisnumber(idx)) {
|
||||
lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v));
|
||||
return cast_int(nvalue(idx));
|
||||
}
|
||||
else { /* constant not found; create a new entry */
|
||||
setnvalue(idx, cast_num(fs->nk));
|
||||
luaM_growvector(L, f->k, fs->nk, f->sizek, TValue,
|
||||
MAXARG_Bx, "constant table overflow");
|
||||
while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
|
||||
setobj(L, &f->k[fs->nk], v);
|
||||
luaC_barrier(L, f, v);
|
||||
return fs->nk++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int luaK_stringK (FuncState *fs, TString *s) {
|
||||
TValue o;
|
||||
setsvalue(fs->L, &o, s);
|
||||
return addk(fs, &o, &o);
|
||||
}
|
||||
|
||||
|
||||
int luaK_numberK (FuncState *fs, lua_Number r) {
|
||||
TValue o;
|
||||
setnvalue(&o, r);
|
||||
return addk(fs, &o, &o);
|
||||
}
|
||||
|
||||
|
||||
static int boolK (FuncState *fs, int b) {
|
||||
TValue o;
|
||||
setbvalue(&o, b);
|
||||
return addk(fs, &o, &o);
|
||||
}
|
||||
|
||||
|
||||
static int nilK (FuncState *fs) {
|
||||
TValue k, v;
|
||||
setnilvalue(&v);
|
||||
/* cannot use nil as key; instead use table itself to represent nil */
|
||||
sethvalue(fs->L, &k, fs->h);
|
||||
return addk(fs, &k, &v);
|
||||
}
|
||||
|
||||
|
||||
void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
|
||||
if (e->k == VCALL) { /* expression is an open function call? */
|
||||
SETARG_C(getcode(fs, e), nresults+1);
|
||||
}
|
||||
else if (e->k == VVARARG) {
|
||||
SETARG_B(getcode(fs, e), nresults+1);
|
||||
SETARG_A(getcode(fs, e), fs->freereg);
|
||||
luaK_reserveregs(fs, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_setoneret (FuncState *fs, expdesc *e) {
|
||||
if (e->k == VCALL) { /* expression is an open function call? */
|
||||
e->k = VNONRELOC;
|
||||
e->u.s.info = GETARG_A(getcode(fs, e));
|
||||
}
|
||||
else if (e->k == VVARARG) {
|
||||
SETARG_B(getcode(fs, e), 2);
|
||||
e->k = VRELOCABLE; /* can relocate its simple result */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_dischargevars (FuncState *fs, expdesc *e) {
|
||||
switch (e->k) {
|
||||
case VLOCAL: {
|
||||
e->k = VNONRELOC;
|
||||
break;
|
||||
}
|
||||
case VUPVAL: {
|
||||
e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0);
|
||||
e->k = VRELOCABLE;
|
||||
break;
|
||||
}
|
||||
case VGLOBAL: {
|
||||
e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info);
|
||||
e->k = VRELOCABLE;
|
||||
break;
|
||||
}
|
||||
case VINDEXED: {
|
||||
freereg(fs, e->u.s.aux);
|
||||
freereg(fs, e->u.s.info);
|
||||
e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux);
|
||||
e->k = VRELOCABLE;
|
||||
break;
|
||||
}
|
||||
case VVARARG:
|
||||
case VCALL: {
|
||||
luaK_setoneret(fs, e);
|
||||
break;
|
||||
}
|
||||
default: break; /* there is one value available (somewhere) */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int code_label (FuncState *fs, int A, int b, int jump) {
|
||||
luaK_getlabel(fs); /* those instructions may be jump targets */
|
||||
return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
|
||||
}
|
||||
|
||||
|
||||
static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
|
||||
luaK_dischargevars(fs, e);
|
||||
switch (e->k) {
|
||||
case VNIL: {
|
||||
luaK_nil(fs, reg, 1);
|
||||
break;
|
||||
}
|
||||
case VFALSE: case VTRUE: {
|
||||
luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
|
||||
break;
|
||||
}
|
||||
case VK: {
|
||||
luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info);
|
||||
break;
|
||||
}
|
||||
case VKNUM: {
|
||||
luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval));
|
||||
break;
|
||||
}
|
||||
case VRELOCABLE: {
|
||||
Instruction *pc = &getcode(fs, e);
|
||||
SETARG_A(*pc, reg);
|
||||
break;
|
||||
}
|
||||
case VNONRELOC: {
|
||||
if (reg != e->u.s.info)
|
||||
luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
lua_assert(e->k == VVOID || e->k == VJMP);
|
||||
return; /* nothing to do... */
|
||||
}
|
||||
}
|
||||
e->u.s.info = reg;
|
||||
e->k = VNONRELOC;
|
||||
}
|
||||
|
||||
|
||||
static void discharge2anyreg (FuncState *fs, expdesc *e) {
|
||||
if (e->k != VNONRELOC) {
|
||||
luaK_reserveregs(fs, 1);
|
||||
discharge2reg(fs, e, fs->freereg-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void exp2reg (FuncState *fs, expdesc *e, int reg) {
|
||||
discharge2reg(fs, e, reg);
|
||||
if (e->k == VJMP)
|
||||
luaK_concat(fs, &e->t, e->u.s.info); /* put this jump in `t' list */
|
||||
if (hasjumps(e)) {
|
||||
int final; /* position after whole expression */
|
||||
int p_f = NO_JUMP; /* position of an eventual LOAD false */
|
||||
int p_t = NO_JUMP; /* position of an eventual LOAD true */
|
||||
if (need_value(fs, e->t) || need_value(fs, e->f)) {
|
||||
int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
|
||||
p_f = code_label(fs, reg, 0, 1);
|
||||
p_t = code_label(fs, reg, 1, 0);
|
||||
luaK_patchtohere(fs, fj);
|
||||
}
|
||||
final = luaK_getlabel(fs);
|
||||
patchlistaux(fs, e->f, final, reg, p_f);
|
||||
patchlistaux(fs, e->t, final, reg, p_t);
|
||||
}
|
||||
e->f = e->t = NO_JUMP;
|
||||
e->u.s.info = reg;
|
||||
e->k = VNONRELOC;
|
||||
}
|
||||
|
||||
|
||||
void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
|
||||
luaK_dischargevars(fs, e);
|
||||
freeexp(fs, e);
|
||||
luaK_reserveregs(fs, 1);
|
||||
exp2reg(fs, e, fs->freereg - 1);
|
||||
}
|
||||
|
||||
|
||||
int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
|
||||
luaK_dischargevars(fs, e);
|
||||
if (e->k == VNONRELOC) {
|
||||
if (!hasjumps(e)) return e->u.s.info; /* exp is already in a register */
|
||||
if (e->u.s.info >= fs->nactvar) { /* reg. is not a local? */
|
||||
exp2reg(fs, e, e->u.s.info); /* put value on it */
|
||||
return e->u.s.info;
|
||||
}
|
||||
}
|
||||
luaK_exp2nextreg(fs, e); /* default */
|
||||
return e->u.s.info;
|
||||
}
|
||||
|
||||
|
||||
void luaK_exp2val (FuncState *fs, expdesc *e) {
|
||||
if (hasjumps(e))
|
||||
luaK_exp2anyreg(fs, e);
|
||||
else
|
||||
luaK_dischargevars(fs, e);
|
||||
}
|
||||
|
||||
|
||||
int luaK_exp2RK (FuncState *fs, expdesc *e) {
|
||||
luaK_exp2val(fs, e);
|
||||
switch (e->k) {
|
||||
case VKNUM:
|
||||
case VTRUE:
|
||||
case VFALSE:
|
||||
case VNIL: {
|
||||
if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */
|
||||
e->u.s.info = (e->k == VNIL) ? nilK(fs) :
|
||||
(e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) :
|
||||
boolK(fs, (e->k == VTRUE));
|
||||
e->k = VK;
|
||||
return RKASK(e->u.s.info);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
case VK: {
|
||||
if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */
|
||||
return RKASK(e->u.s.info);
|
||||
else break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
/* not a constant in the right range: put it in a register */
|
||||
return luaK_exp2anyreg(fs, e);
|
||||
}
|
||||
|
||||
|
||||
void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
|
||||
switch (var->k) {
|
||||
case VLOCAL: {
|
||||
freeexp(fs, ex);
|
||||
exp2reg(fs, ex, var->u.s.info);
|
||||
return;
|
||||
}
|
||||
case VUPVAL: {
|
||||
int e = luaK_exp2anyreg(fs, ex);
|
||||
luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0);
|
||||
break;
|
||||
}
|
||||
case VGLOBAL: {
|
||||
int e = luaK_exp2anyreg(fs, ex);
|
||||
luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info);
|
||||
break;
|
||||
}
|
||||
case VINDEXED: {
|
||||
int e = luaK_exp2RK(fs, ex);
|
||||
luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
lua_assert(0); /* invalid var kind to store */
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeexp(fs, ex);
|
||||
}
|
||||
|
||||
|
||||
void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
|
||||
int func;
|
||||
luaK_exp2anyreg(fs, e);
|
||||
freeexp(fs, e);
|
||||
func = fs->freereg;
|
||||
luaK_reserveregs(fs, 2);
|
||||
luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key));
|
||||
freeexp(fs, key);
|
||||
e->u.s.info = func;
|
||||
e->k = VNONRELOC;
|
||||
}
|
||||
|
||||
|
||||
static void invertjump (FuncState *fs, expdesc *e) {
|
||||
Instruction *pc = getjumpcontrol(fs, e->u.s.info);
|
||||
lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
|
||||
GET_OPCODE(*pc) != OP_TEST);
|
||||
SETARG_A(*pc, !(GETARG_A(*pc)));
|
||||
}
|
||||
|
||||
|
||||
static int jumponcond (FuncState *fs, expdesc *e, int cond) {
|
||||
if (e->k == VRELOCABLE) {
|
||||
Instruction ie = getcode(fs, e);
|
||||
if (GET_OPCODE(ie) == OP_NOT) {
|
||||
fs->pc--; /* remove previous OP_NOT */
|
||||
return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
|
||||
}
|
||||
/* else go through */
|
||||
}
|
||||
discharge2anyreg(fs, e);
|
||||
freeexp(fs, e);
|
||||
return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond);
|
||||
}
|
||||
|
||||
|
||||
void luaK_goiftrue (FuncState *fs, expdesc *e) {
|
||||
int pc; /* pc of last jump */
|
||||
luaK_dischargevars(fs, e);
|
||||
switch (e->k) {
|
||||
case VK: case VKNUM: case VTRUE: {
|
||||
pc = NO_JUMP; /* always true; do nothing */
|
||||
break;
|
||||
}
|
||||
case VFALSE: {
|
||||
pc = luaK_jump(fs); /* always jump */
|
||||
break;
|
||||
}
|
||||
case VJMP: {
|
||||
invertjump(fs, e);
|
||||
pc = e->u.s.info;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
pc = jumponcond(fs, e, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */
|
||||
luaK_patchtohere(fs, e->t);
|
||||
e->t = NO_JUMP;
|
||||
}
|
||||
|
||||
|
||||
static void luaK_goiffalse (FuncState *fs, expdesc *e) {
|
||||
int pc; /* pc of last jump */
|
||||
luaK_dischargevars(fs, e);
|
||||
switch (e->k) {
|
||||
case VNIL: case VFALSE: {
|
||||
pc = NO_JUMP; /* always false; do nothing */
|
||||
break;
|
||||
}
|
||||
case VTRUE: {
|
||||
pc = luaK_jump(fs); /* always jump */
|
||||
break;
|
||||
}
|
||||
case VJMP: {
|
||||
pc = e->u.s.info;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
pc = jumponcond(fs, e, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */
|
||||
luaK_patchtohere(fs, e->f);
|
||||
e->f = NO_JUMP;
|
||||
}
|
||||
|
||||
|
||||
static void codenot (FuncState *fs, expdesc *e) {
|
||||
luaK_dischargevars(fs, e);
|
||||
switch (e->k) {
|
||||
case VNIL: case VFALSE: {
|
||||
e->k = VTRUE;
|
||||
break;
|
||||
}
|
||||
case VK: case VKNUM: case VTRUE: {
|
||||
e->k = VFALSE;
|
||||
break;
|
||||
}
|
||||
case VJMP: {
|
||||
invertjump(fs, e);
|
||||
break;
|
||||
}
|
||||
case VRELOCABLE:
|
||||
case VNONRELOC: {
|
||||
discharge2anyreg(fs, e);
|
||||
freeexp(fs, e);
|
||||
e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0);
|
||||
e->k = VRELOCABLE;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
lua_assert(0); /* cannot happen */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* interchange true and false lists */
|
||||
{ int temp = e->f; e->f = e->t; e->t = temp; }
|
||||
removevalues(fs, e->f);
|
||||
removevalues(fs, e->t);
|
||||
}
|
||||
|
||||
|
||||
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
|
||||
t->u.s.aux = luaK_exp2RK(fs, k);
|
||||
t->k = VINDEXED;
|
||||
}
|
||||
|
||||
|
||||
static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
|
||||
lua_Number v1, v2, r;
|
||||
if (!isnumeral(e1) || !isnumeral(e2)) return 0;
|
||||
v1 = e1->u.nval;
|
||||
v2 = e2->u.nval;
|
||||
switch (op) {
|
||||
case OP_ADD: r = luai_numadd(v1, v2); break;
|
||||
case OP_SUB: r = luai_numsub(v1, v2); break;
|
||||
case OP_MUL: r = luai_nummul(v1, v2); break;
|
||||
case OP_DIV:
|
||||
if (v2 == 0) return 0; /* do not attempt to divide by 0 */
|
||||
r = luai_numdiv(v1, v2); break;
|
||||
case OP_MOD:
|
||||
if (v2 == 0) return 0; /* do not attempt to divide by 0 */
|
||||
r = luai_nummod(v1, v2); break;
|
||||
case OP_POW: r = luai_numpow(v1, v2); break;
|
||||
case OP_UNM: r = luai_numunm(v1); break;
|
||||
case OP_LEN: return 0; /* no constant folding for 'len' */
|
||||
default: lua_assert(0); r = 0; break;
|
||||
}
|
||||
if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */
|
||||
e1->u.nval = r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
|
||||
if (constfolding(op, e1, e2))
|
||||
return;
|
||||
else {
|
||||
int o1 = luaK_exp2RK(fs, e1);
|
||||
int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0;
|
||||
freeexp(fs, e2);
|
||||
freeexp(fs, e1);
|
||||
e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2);
|
||||
e1->k = VRELOCABLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
|
||||
expdesc *e2) {
|
||||
int o1 = luaK_exp2RK(fs, e1);
|
||||
int o2 = luaK_exp2RK(fs, e2);
|
||||
freeexp(fs, e2);
|
||||
freeexp(fs, e1);
|
||||
if (cond == 0 && op != OP_EQ) {
|
||||
int temp; /* exchange args to replace by `<' or `<=' */
|
||||
temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */
|
||||
cond = 1;
|
||||
}
|
||||
e1->u.s.info = condjump(fs, op, cond, o1, o2);
|
||||
e1->k = VJMP;
|
||||
}
|
||||
|
||||
|
||||
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
|
||||
expdesc e2;
|
||||
e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
|
||||
switch (op) {
|
||||
case OPR_MINUS: {
|
||||
if (e->k == VK)
|
||||
luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */
|
||||
codearith(fs, OP_UNM, e, &e2);
|
||||
break;
|
||||
}
|
||||
case OPR_NOT: codenot(fs, e); break;
|
||||
case OPR_LEN: {
|
||||
luaK_exp2anyreg(fs, e); /* cannot operate on constants */
|
||||
codearith(fs, OP_LEN, e, &e2);
|
||||
break;
|
||||
}
|
||||
default: lua_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
|
||||
switch (op) {
|
||||
case OPR_AND: {
|
||||
luaK_goiftrue(fs, v);
|
||||
break;
|
||||
}
|
||||
case OPR_OR: {
|
||||
luaK_goiffalse(fs, v);
|
||||
break;
|
||||
}
|
||||
case OPR_CONCAT: {
|
||||
luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (!isnumeral(v)) luaK_exp2RK(fs, v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
|
||||
switch (op) {
|
||||
case OPR_AND: {
|
||||
lua_assert(e1->t == NO_JUMP); /* list must be closed */
|
||||
luaK_dischargevars(fs, e2);
|
||||
luaK_concat(fs, &e1->f, e2->f);
|
||||
e1->k = e2->k; e1->u.s.info = e2->u.s.info;
|
||||
e1->u.s.aux = e2->u.s.aux; e1->t = e2->t;
|
||||
break;
|
||||
}
|
||||
case OPR_OR: {
|
||||
lua_assert(e1->f == NO_JUMP); /* list must be closed */
|
||||
luaK_dischargevars(fs, e2);
|
||||
luaK_concat(fs, &e1->t, e2->t);
|
||||
e1->k = e2->k; e1->u.s.info = e2->u.s.info;
|
||||
e1->u.s.aux = e2->u.s.aux; e1->f = e2->f;
|
||||
break;
|
||||
}
|
||||
case OPR_CONCAT: {
|
||||
luaK_exp2val(fs, e2);
|
||||
if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
|
||||
lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1);
|
||||
freeexp(fs, e1);
|
||||
SETARG_B(getcode(fs, e2), e1->u.s.info);
|
||||
e1->k = e2->k; e1->u.s.info = e2->u.s.info;
|
||||
}
|
||||
else {
|
||||
luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
|
||||
codearith(fs, OP_CONCAT, e1, e2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break;
|
||||
case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break;
|
||||
case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break;
|
||||
case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break;
|
||||
case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break;
|
||||
case OPR_POW: codearith(fs, OP_POW, e1, e2); break;
|
||||
case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break;
|
||||
case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break;
|
||||
case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break;
|
||||
case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break;
|
||||
case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break;
|
||||
case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break;
|
||||
default: lua_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaK_fixline (FuncState *fs, int line) {
|
||||
fs->f->lineinfo[fs->pc - 1] = line;
|
||||
}
|
||||
|
||||
|
||||
static int luaK_code (FuncState *fs, Instruction i, int line) {
|
||||
Proto *f = fs->f;
|
||||
dischargejpc(fs); /* `pc' will change */
|
||||
/* put new instruction in code array */
|
||||
luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction,
|
||||
MAX_INT, "code size overflow");
|
||||
f->code[fs->pc] = i;
|
||||
/* save corresponding line information */
|
||||
luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
|
||||
MAX_INT, "code size overflow");
|
||||
f->lineinfo[fs->pc] = line;
|
||||
return fs->pc++;
|
||||
}
|
||||
|
||||
|
||||
int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
|
||||
lua_assert(getOpMode(o) == iABC);
|
||||
lua_assert(getBMode(o) != OpArgN || b == 0);
|
||||
lua_assert(getCMode(o) != OpArgN || c == 0);
|
||||
return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline);
|
||||
}
|
||||
|
||||
|
||||
int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
|
||||
lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
|
||||
lua_assert(getCMode(o) == OpArgN);
|
||||
return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline);
|
||||
}
|
||||
|
||||
|
||||
void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
|
||||
int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1;
|
||||
int b = (tostore == LUA_MULTRET) ? 0 : tostore;
|
||||
lua_assert(tostore != 0);
|
||||
if (c <= MAXARG_C)
|
||||
luaK_codeABC(fs, OP_SETLIST, base, b, c);
|
||||
else {
|
||||
luaK_codeABC(fs, OP_SETLIST, base, b, 0);
|
||||
luaK_code(fs, cast(Instruction, c), fs->ls->lastline);
|
||||
}
|
||||
fs->freereg = base + 1; /* free registers with list values */
|
||||
}
|
||||
|
77
src/lua/lcode.h
Normal file
77
src/lua/lcode.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
** $Id: lcode.h,v 1.47 2005/11/08 19:44:31 roberto Exp $
|
||||
** Code generator for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef lcode_h
|
||||
#define lcode_h
|
||||
|
||||
#include "llex.h"
|
||||
#include "lobject.h"
|
||||
#include "lopcodes.h"
|
||||
#include "lparser.h"
|
||||
|
||||
|
||||
/*
|
||||
** Marks the end of a patch list. It is an invalid value both as an absolute
|
||||
** address, and as a list link (would link an element to itself).
|
||||
*/
|
||||
#define NO_JUMP (-1)
|
||||
|
||||
|
||||
/*
|
||||
** grep "ORDER OPR" if you change these enums
|
||||
*/
|
||||
typedef enum BinOpr {
|
||||
OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW,
|
||||
OPR_CONCAT,
|
||||
OPR_NE, OPR_EQ,
|
||||
OPR_LT, OPR_LE, OPR_GT, OPR_GE,
|
||||
OPR_AND, OPR_OR,
|
||||
OPR_NOBINOPR
|
||||
} BinOpr;
|
||||
|
||||
#define binopistest(op) ((op) >= OPR_NE)
|
||||
|
||||
typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
|
||||
|
||||
|
||||
#define getcode(fs,e) ((fs)->f->code[(e)->u.s.info])
|
||||
|
||||
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
|
||||
|
||||
#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET)
|
||||
|
||||
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
|
||||
LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
|
||||
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
|
||||
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
|
||||
LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
|
||||
LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
|
||||
LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s);
|
||||
LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r);
|
||||
LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
|
||||
LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
|
||||
LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
|
||||
LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
|
||||
LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC int luaK_jump (FuncState *fs);
|
||||
LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret);
|
||||
LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);
|
||||
LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
|
||||
LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);
|
||||
LUAI_FUNC int luaK_getlabel (FuncState *fs);
|
||||
LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v);
|
||||
LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
|
||||
LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2);
|
||||
LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
|
||||
|
||||
|
||||
#endif
|
397
src/lua/ldblib.c
Normal file
397
src/lua/ldblib.c
Normal file
@ -0,0 +1,397 @@
|
||||
/*
|
||||
** $Id: ldblib.c,v 1.104 2005/12/29 15:32:11 roberto Exp $
|
||||
** Interface from Lua to its debug API
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ldblib_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
|
||||
|
||||
static int db_getregistry (lua_State *L) {
|
||||
lua_pushvalue(L, LUA_REGISTRYINDEX);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_getmetatable (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
if (!lua_getmetatable(L, 1)) {
|
||||
lua_pushnil(L); /* no metatable */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_setmetatable (lua_State *L) {
|
||||
int t = lua_type(L, 2);
|
||||
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
|
||||
"nil or table expected");
|
||||
lua_settop(L, 2);
|
||||
lua_pushboolean(L, lua_setmetatable(L, 1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_getfenv (lua_State *L) {
|
||||
lua_getfenv(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_setfenv (lua_State *L) {
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
lua_settop(L, 2);
|
||||
if (lua_setfenv(L, 1) == 0)
|
||||
luaL_error(L, LUA_QL("setfenv")
|
||||
" cannot change environment of given object");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void settabss (lua_State *L, const char *i, const char *v) {
|
||||
lua_pushstring(L, v);
|
||||
lua_setfield(L, -2, i);
|
||||
}
|
||||
|
||||
|
||||
static void settabsi (lua_State *L, const char *i, int v) {
|
||||
lua_pushinteger(L, v);
|
||||
lua_setfield(L, -2, i);
|
||||
}
|
||||
|
||||
|
||||
static lua_State *getthread (lua_State *L, int *arg) {
|
||||
if (lua_isthread(L, 1)) {
|
||||
*arg = 1;
|
||||
return lua_tothread(L, 1);
|
||||
}
|
||||
else {
|
||||
*arg = 0;
|
||||
return L;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
|
||||
if (L == L1) {
|
||||
lua_pushvalue(L, -2);
|
||||
lua_remove(L, -3);
|
||||
}
|
||||
else
|
||||
lua_xmove(L1, L, 1);
|
||||
lua_setfield(L, -2, fname);
|
||||
}
|
||||
|
||||
|
||||
static int db_getinfo (lua_State *L) {
|
||||
lua_Debug ar;
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
const char *options = luaL_optstring(L, arg+2, "flnSu");
|
||||
if (lua_isnumber(L, arg+1)) {
|
||||
if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
|
||||
lua_pushnil(L); /* level out of range */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (lua_isfunction(L, arg+1)) {
|
||||
lua_pushfstring(L, ">%s", options);
|
||||
options = lua_tostring(L, -1);
|
||||
lua_pushvalue(L, arg+1);
|
||||
lua_xmove(L, L1, 1);
|
||||
}
|
||||
else
|
||||
return luaL_argerror(L, arg+1, "function or level expected");
|
||||
if (!lua_getinfo(L1, options, &ar))
|
||||
return luaL_argerror(L, arg+2, "invalid option");
|
||||
lua_createtable(L, 0, 2);
|
||||
if (strchr(options, 'S')) {
|
||||
settabss(L, "source", ar.source);
|
||||
settabss(L, "short_src", ar.short_src);
|
||||
settabsi(L, "linedefined", ar.linedefined);
|
||||
settabsi(L, "lastlinedefined", ar.lastlinedefined);
|
||||
settabss(L, "what", ar.what);
|
||||
}
|
||||
if (strchr(options, 'l'))
|
||||
settabsi(L, "currentline", ar.currentline);
|
||||
if (strchr(options, 'u'))
|
||||
settabsi(L, "nups", ar.nups);
|
||||
if (strchr(options, 'n')) {
|
||||
settabss(L, "name", ar.name);
|
||||
settabss(L, "namewhat", ar.namewhat);
|
||||
}
|
||||
if (strchr(options, 'L'))
|
||||
treatstackoption(L, L1, "activelines");
|
||||
if (strchr(options, 'f'))
|
||||
treatstackoption(L, L1, "func");
|
||||
return 1; /* return table */
|
||||
}
|
||||
|
||||
|
||||
static int db_getlocal (lua_State *L) {
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
lua_Debug ar;
|
||||
const char *name;
|
||||
if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
|
||||
return luaL_argerror(L, arg+1, "level out of range");
|
||||
name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2));
|
||||
if (name) {
|
||||
lua_xmove(L1, L, 1);
|
||||
lua_pushstring(L, name);
|
||||
lua_pushvalue(L, -2);
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int db_setlocal (lua_State *L) {
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
lua_Debug ar;
|
||||
if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
|
||||
return luaL_argerror(L, arg+1, "level out of range");
|
||||
luaL_checkany(L, arg+3);
|
||||
lua_settop(L, arg+3);
|
||||
lua_xmove(L, L1, 1);
|
||||
lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int auxupvalue (lua_State *L, int get) {
|
||||
const char *name;
|
||||
int n = luaL_checkint(L, 2);
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */
|
||||
name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
|
||||
if (name == NULL) return 0;
|
||||
lua_pushstring(L, name);
|
||||
lua_insert(L, -(get+1));
|
||||
return get + 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_getupvalue (lua_State *L) {
|
||||
return auxupvalue(L, 1);
|
||||
}
|
||||
|
||||
|
||||
static int db_setupvalue (lua_State *L) {
|
||||
luaL_checkany(L, 3);
|
||||
return auxupvalue(L, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const char KEY_HOOK = 'h';
|
||||
|
||||
|
||||
static void hookf (lua_State *L, lua_Debug *ar) {
|
||||
static const char *const hooknames[] =
|
||||
{"call", "return", "line", "count", "tail return"};
|
||||
lua_pushlightuserdata(L, (void *)&KEY_HOOK);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_pushlightuserdata(L, L);
|
||||
lua_rawget(L, -2);
|
||||
if (lua_isfunction(L, -1)) {
|
||||
lua_pushstring(L, hooknames[(int)ar->event]);
|
||||
if (ar->currentline >= 0)
|
||||
lua_pushinteger(L, ar->currentline);
|
||||
else lua_pushnil(L);
|
||||
lua_assert(lua_getinfo(L, "lS", ar));
|
||||
lua_call(L, 2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int makemask (const char *smask, int count) {
|
||||
int mask = 0;
|
||||
if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
|
||||
if (strchr(smask, 'r')) mask |= LUA_MASKRET;
|
||||
if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
|
||||
if (count > 0) mask |= LUA_MASKCOUNT;
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
||||
static char *unmakemask (int mask, char *smask) {
|
||||
int i = 0;
|
||||
if (mask & LUA_MASKCALL) smask[i++] = 'c';
|
||||
if (mask & LUA_MASKRET) smask[i++] = 'r';
|
||||
if (mask & LUA_MASKLINE) smask[i++] = 'l';
|
||||
smask[i] = '\0';
|
||||
return smask;
|
||||
}
|
||||
|
||||
|
||||
static void gethooktable (lua_State *L) {
|
||||
lua_pushlightuserdata(L, (void *)&KEY_HOOK);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
if (!lua_istable(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
lua_createtable(L, 0, 1);
|
||||
lua_pushlightuserdata(L, (void *)&KEY_HOOK);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int db_sethook (lua_State *L) {
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
if (lua_isnoneornil(L, arg+1)) {
|
||||
lua_settop(L, arg+1);
|
||||
lua_sethook(L1, NULL, 0, 0); /* turn off hooks */
|
||||
}
|
||||
else {
|
||||
const char *smask = luaL_checkstring(L, arg+2);
|
||||
int count = luaL_optint(L, arg+3, 0);
|
||||
luaL_checktype(L, arg+1, LUA_TFUNCTION);
|
||||
lua_sethook(L1, hookf, makemask(smask, count), count);
|
||||
}
|
||||
gethooktable(L1);
|
||||
lua_pushlightuserdata(L1, L1);
|
||||
lua_pushvalue(L, arg+1);
|
||||
lua_xmove(L, L1, 1);
|
||||
lua_rawset(L1, -3); /* set new hook */
|
||||
lua_pop(L1, 1); /* remove hook table */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int db_gethook (lua_State *L) {
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
char buff[5];
|
||||
int mask = lua_gethookmask(L1);
|
||||
lua_Hook hook = lua_gethook(L1);
|
||||
if (hook != NULL && hook != hookf) /* external hook? */
|
||||
lua_pushliteral(L, "external hook");
|
||||
else {
|
||||
gethooktable(L1);
|
||||
lua_pushlightuserdata(L1, L1);
|
||||
lua_rawget(L1, -2); /* get hook */
|
||||
lua_remove(L1, -2); /* remove hook table */
|
||||
lua_xmove(L1, L, 1);
|
||||
}
|
||||
lua_pushstring(L, unmakemask(mask, buff));
|
||||
lua_pushinteger(L, lua_gethookcount(L1));
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
static int db_debug (lua_State *L) {
|
||||
for (;;) {
|
||||
char buffer[250];
|
||||
fputs("lua_debug> ", stderr);
|
||||
if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
|
||||
strcmp(buffer, "cont\n") == 0)
|
||||
return 0;
|
||||
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
|
||||
lua_pcall(L, 0, 0, 0)) {
|
||||
fputs(lua_tostring(L, -1), stderr);
|
||||
fputs("\n", stderr);
|
||||
}
|
||||
lua_settop(L, 0); /* remove eventual returns */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define LEVELS1 12 /* size of the first part of the stack */
|
||||
#define LEVELS2 10 /* size of the second part of the stack */
|
||||
|
||||
static int db_errorfb (lua_State *L) {
|
||||
int level;
|
||||
int firstpart = 1; /* still before eventual `...' */
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
lua_Debug ar;
|
||||
if (lua_isnumber(L, arg+2)) {
|
||||
level = (int)lua_tointeger(L, arg+2);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
else
|
||||
level = (L == L1) ? 1 : 0; /* level 0 may be this own function */
|
||||
if (lua_gettop(L) == arg)
|
||||
lua_pushliteral(L, "");
|
||||
else if (!lua_isstring(L, arg+1)) return 1; /* message is not a string */
|
||||
else lua_pushliteral(L, "\n");
|
||||
lua_pushliteral(L, "stack traceback:");
|
||||
while (lua_getstack(L1, level++, &ar)) {
|
||||
if (level > LEVELS1 && firstpart) {
|
||||
/* no more than `LEVELS2' more levels? */
|
||||
if (!lua_getstack(L1, level+LEVELS2, &ar))
|
||||
level--; /* keep going */
|
||||
else {
|
||||
lua_pushliteral(L, "\n\t..."); /* too many levels */
|
||||
while (lua_getstack(L1, level+LEVELS2, &ar)) /* find last levels */
|
||||
level++;
|
||||
}
|
||||
firstpart = 0;
|
||||
continue;
|
||||
}
|
||||
lua_pushliteral(L, "\n\t");
|
||||
lua_getinfo(L1, "Snl", &ar);
|
||||
lua_pushfstring(L, "%s:", ar.short_src);
|
||||
if (ar.currentline > 0)
|
||||
lua_pushfstring(L, "%d:", ar.currentline);
|
||||
if (*ar.namewhat != '\0') /* is there a name? */
|
||||
lua_pushfstring(L, " in function " LUA_QS, ar.name);
|
||||
else {
|
||||
if (*ar.what == 'm') /* main? */
|
||||
lua_pushfstring(L, " in main chunk");
|
||||
else if (*ar.what == 'C' || *ar.what == 't')
|
||||
lua_pushliteral(L, " ?"); /* C function or tail call */
|
||||
else
|
||||
lua_pushfstring(L, " in function <%s:%d>",
|
||||
ar.short_src, ar.linedefined);
|
||||
}
|
||||
lua_concat(L, lua_gettop(L) - arg);
|
||||
}
|
||||
lua_concat(L, lua_gettop(L) - arg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static const luaL_Reg dblib[] = {
|
||||
{"debug", db_debug},
|
||||
{"getfenv", db_getfenv},
|
||||
{"gethook", db_gethook},
|
||||
{"getinfo", db_getinfo},
|
||||
{"getlocal", db_getlocal},
|
||||
{"getregistry", db_getregistry},
|
||||
{"getmetatable", db_getmetatable},
|
||||
{"getupvalue", db_getupvalue},
|
||||
{"setfenv", db_setfenv},
|
||||
{"sethook", db_sethook},
|
||||
{"setlocal", db_setlocal},
|
||||
{"setmetatable", db_setmetatable},
|
||||
{"setupvalue", db_setupvalue},
|
||||
{"traceback", db_errorfb},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
LUALIB_API int luaopen_debug (lua_State *L) {
|
||||
luaL_register(L, LUA_DBLIBNAME, dblib);
|
||||
return 1;
|
||||
}
|
||||
|
620
src/lua/ldebug.c
Normal file
620
src/lua/ldebug.c
Normal file
@ -0,0 +1,620 @@
|
||||
/*
|
||||
** $Id: ldebug.c,v 2.29 2005/12/22 16:19:56 roberto Exp $
|
||||
** Debug Interface
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define ldebug_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lapi.h"
|
||||
#include "lcode.h"
|
||||
#include "ldebug.h"
|
||||
#include "ldo.h"
|
||||
#include "lfunc.h"
|
||||
#include "lobject.h"
|
||||
#include "lopcodes.h"
|
||||
#include "lstate.h"
|
||||
#include "lstring.h"
|
||||
#include "ltable.h"
|
||||
#include "ltm.h"
|
||||
#include "lvm.h"
|
||||
|
||||
|
||||
|
||||
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
|
||||
|
||||
|
||||
static int currentpc (lua_State *L, CallInfo *ci) {
|
||||
if (!isLua(ci)) return -1; /* function is not a Lua function? */
|
||||
if (ci == L->ci)
|
||||
ci->savedpc = L->savedpc;
|
||||
return pcRel(ci->savedpc, ci_func(ci)->l.p);
|
||||
}
|
||||
|
||||
|
||||
static int currentline (lua_State *L, CallInfo *ci) {
|
||||
int pc = currentpc(L, ci);
|
||||
if (pc < 0)
|
||||
return -1; /* only active lua functions have current-line information */
|
||||
else
|
||||
return getline(ci_func(ci)->l.p, pc);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** this function can be called asynchronous (e.g. during a signal)
|
||||
*/
|
||||
LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
|
||||
if (func == NULL || mask == 0) { /* turn off hooks? */
|
||||
mask = 0;
|
||||
func = NULL;
|
||||
}
|
||||
L->hook = func;
|
||||
L->basehookcount = count;
|
||||
resethookcount(L);
|
||||
L->hookmask = cast_byte(mask);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
LUA_API lua_Hook lua_gethook (lua_State *L) {
|
||||
return L->hook;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_gethookmask (lua_State *L) {
|
||||
return L->hookmask;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_gethookcount (lua_State *L) {
|
||||
return L->basehookcount;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
|
||||
int status;
|
||||
CallInfo *ci;
|
||||
lua_lock(L);
|
||||
for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) {
|
||||
level--;
|
||||
if (f_isLua(ci)) /* Lua function? */
|
||||
level -= ci->tailcalls; /* skip lost tail calls */
|
||||
}
|
||||
if (level == 0 && ci > L->base_ci) { /* level found? */
|
||||
status = 1;
|
||||
ar->i_ci = cast_int(ci - L->base_ci);
|
||||
}
|
||||
else if (level < 0) { /* level is of a lost tail call? */
|
||||
status = 1;
|
||||
ar->i_ci = 0;
|
||||
}
|
||||
else status = 0; /* no such level */
|
||||
lua_unlock(L);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static Proto *getluaproto (CallInfo *ci) {
|
||||
return (isLua(ci) ? ci_func(ci)->l.p : NULL);
|
||||
}
|
||||
|
||||
|
||||
static const char *findlocal (lua_State *L, CallInfo *ci, int n) {
|
||||
const char *name;
|
||||
Proto *fp = getluaproto(ci);
|
||||
if (fp && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != NULL)
|
||||
return name; /* is a local variable in a Lua function */
|
||||
else {
|
||||
StkId limit = (ci == L->ci) ? L->top : (ci+1)->func;
|
||||
if (limit - ci->base >= n && n > 0) /* is 'n' inside 'ci' stack? */
|
||||
return "(*temporary)";
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
|
||||
CallInfo *ci = L->base_ci + ar->i_ci;
|
||||
const char *name = findlocal(L, ci, n);
|
||||
lua_lock(L);
|
||||
if (name)
|
||||
luaA_pushobject(L, ci->base + (n - 1));
|
||||
lua_unlock(L);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
|
||||
CallInfo *ci = L->base_ci + ar->i_ci;
|
||||
const char *name = findlocal(L, ci, n);
|
||||
lua_lock(L);
|
||||
if (name)
|
||||
setobjs2s(L, ci->base + (n - 1), L->top - 1);
|
||||
L->top--; /* pop value */
|
||||
lua_unlock(L);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
static void funcinfo (lua_Debug *ar, Closure *cl) {
|
||||
if (cl->c.isC) {
|
||||
ar->source = "=[C]";
|
||||
ar->linedefined = -1;
|
||||
ar->lastlinedefined = -1;
|
||||
ar->what = "C";
|
||||
}
|
||||
else {
|
||||
ar->source = getstr(cl->l.p->source);
|
||||
ar->linedefined = cl->l.p->linedefined;
|
||||
ar->lastlinedefined = cl->l.p->lastlinedefined;
|
||||
ar->what = (ar->linedefined == 0) ? "main" : "Lua";
|
||||
}
|
||||
luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
|
||||
}
|
||||
|
||||
|
||||
static void info_tailcall (lua_Debug *ar) {
|
||||
ar->name = ar->namewhat = "";
|
||||
ar->what = "tail";
|
||||
ar->lastlinedefined = ar->linedefined = ar->currentline = -1;
|
||||
ar->source = "=(tail call)";
|
||||
luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
|
||||
ar->nups = 0;
|
||||
}
|
||||
|
||||
|
||||
static void collectvalidlines (lua_State *L, Closure *f) {
|
||||
if (f == NULL || f->c.isC) {
|
||||
setnilvalue(L->top);
|
||||
}
|
||||
else {
|
||||
Table *t = luaH_new(L, 0, 0);
|
||||
int *lineinfo = f->l.p->lineinfo;
|
||||
int i;
|
||||
for (i=0; i<f->l.p->sizelineinfo; i++)
|
||||
setbvalue(luaH_setnum(L, t, lineinfo[i]), 1);
|
||||
sethvalue(L, L->top, t);
|
||||
}
|
||||
incr_top(L);
|
||||
}
|
||||
|
||||
|
||||
static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
||||
Closure *f, CallInfo *ci) {
|
||||
int status = 1;
|
||||
if (f == NULL) {
|
||||
info_tailcall(ar);
|
||||
return status;
|
||||
}
|
||||
for (; *what; what++) {
|
||||
switch (*what) {
|
||||
case 'S': {
|
||||
funcinfo(ar, f);
|
||||
break;
|
||||
}
|
||||
case 'l': {
|
||||
ar->currentline = (ci) ? currentline(L, ci) : -1;
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
ar->nups = f->c.nupvalues;
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL;
|
||||
if (ar->namewhat == NULL) {
|
||||
ar->namewhat = ""; /* not found */
|
||||
ar->name = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'L':
|
||||
case 'f': /* handled by lua_getinfo */
|
||||
break;
|
||||
default: status = 0; /* invalid option */
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
|
||||
int status;
|
||||
Closure *f = NULL;
|
||||
CallInfo *ci = NULL;
|
||||
lua_lock(L);
|
||||
if (*what == '>') {
|
||||
StkId func = L->top - 1;
|
||||
luai_apicheck(L, ttisfunction(func));
|
||||
what++; /* skip the '>' */
|
||||
f = clvalue(func);
|
||||
L->top--; /* pop function */
|
||||
}
|
||||
else if (ar->i_ci != 0) { /* no tail call? */
|
||||
ci = L->base_ci + ar->i_ci;
|
||||
lua_assert(ttisfunction(ci->func));
|
||||
f = clvalue(ci->func);
|
||||
}
|
||||
status = auxgetinfo(L, what, ar, f, ci);
|
||||
if (strchr(what, 'f')) {
|
||||
if (f == NULL) setnilvalue(L->top);
|
||||
else setclvalue(L, L->top, f);
|
||||
incr_top(L);
|
||||
}
|
||||
if (strchr(what, 'L'))
|
||||
collectvalidlines(L, f);
|
||||
lua_unlock(L);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Symbolic Execution and code checker
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
#define check(x) if (!(x)) return 0;
|
||||
|
||||
#define checkjump(pt,pc) check(0 <= pc && pc < pt->sizecode)
|
||||
|
||||
#define checkreg(pt,reg) check((reg) < (pt)->maxstacksize)
|
||||
|
||||
|
||||
|
||||
static int precheck (const Proto *pt) {
|
||||
check(pt->maxstacksize <= MAXSTACK);
|
||||
lua_assert(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize);
|
||||
lua_assert(!(pt->is_vararg & VARARG_NEEDSARG) ||
|
||||
(pt->is_vararg & VARARG_HASARG));
|
||||
check(pt->sizeupvalues <= pt->nups);
|
||||
check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0);
|
||||
check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#define checkopenop(pt,pc) luaG_checkopenop((pt)->code[(pc)+1])
|
||||
|
||||
int luaG_checkopenop (Instruction i) {
|
||||
switch (GET_OPCODE(i)) {
|
||||
case OP_CALL:
|
||||
case OP_TAILCALL:
|
||||
case OP_RETURN:
|
||||
case OP_SETLIST: {
|
||||
check(GETARG_B(i) == 0);
|
||||
return 1;
|
||||
}
|
||||
default: return 0; /* invalid instruction after an open call */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) {
|
||||
switch (mode) {
|
||||
case OpArgN: check(r == 0); break;
|
||||
case OpArgU: break;
|
||||
case OpArgR: checkreg(pt, r); break;
|
||||
case OpArgK:
|
||||
check(ISK(r) ? INDEXK(r) < pt->sizek : r < pt->maxstacksize);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static Instruction symbexec (const Proto *pt, int lastpc, int reg) {
|
||||
int pc;
|
||||
int last; /* stores position of last instruction that changed `reg' */
|
||||
last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */
|
||||
check(precheck(pt));
|
||||
for (pc = 0; pc < lastpc; pc++) {
|
||||
Instruction i = pt->code[pc];
|
||||
OpCode op = GET_OPCODE(i);
|
||||
int a = GETARG_A(i);
|
||||
int b = 0;
|
||||
int c = 0;
|
||||
check(op < NUM_OPCODES);
|
||||
checkreg(pt, a);
|
||||
switch (getOpMode(op)) {
|
||||
case iABC: {
|
||||
b = GETARG_B(i);
|
||||
c = GETARG_C(i);
|
||||
check(checkArgMode(pt, b, getBMode(op)));
|
||||
check(checkArgMode(pt, c, getCMode(op)));
|
||||
break;
|
||||
}
|
||||
case iABx: {
|
||||
b = GETARG_Bx(i);
|
||||
if (getBMode(op) == OpArgK) check(b < pt->sizek);
|
||||
break;
|
||||
}
|
||||
case iAsBx: {
|
||||
b = GETARG_sBx(i);
|
||||
if (getBMode(op) == OpArgR) {
|
||||
int dest = pc+1+b;
|
||||
check(0 <= dest && dest < pt->sizecode);
|
||||
if (dest > 0) {
|
||||
/* cannot jump to a setlist count */
|
||||
Instruction d = pt->code[dest-1];
|
||||
check(!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (testAMode(op)) {
|
||||
if (a == reg) last = pc; /* change register `a' */
|
||||
}
|
||||
if (testTMode(op)) {
|
||||
check(pc+2 < pt->sizecode); /* check skip */
|
||||
check(GET_OPCODE(pt->code[pc+1]) == OP_JMP);
|
||||
}
|
||||
switch (op) {
|
||||
case OP_LOADBOOL: {
|
||||
check(c == 0 || pc+2 < pt->sizecode); /* check its jump */
|
||||
break;
|
||||
}
|
||||
case OP_LOADNIL: {
|
||||
if (a <= reg && reg <= b)
|
||||
last = pc; /* set registers from `a' to `b' */
|
||||
break;
|
||||
}
|
||||
case OP_GETUPVAL:
|
||||
case OP_SETUPVAL: {
|
||||
check(b < pt->nups);
|
||||
break;
|
||||
}
|
||||
case OP_GETGLOBAL:
|
||||
case OP_SETGLOBAL: {
|
||||
check(ttisstring(&pt->k[b]));
|
||||
break;
|
||||
}
|
||||
case OP_SELF: {
|
||||
checkreg(pt, a+1);
|
||||
if (reg == a+1) last = pc;
|
||||
break;
|
||||
}
|
||||
case OP_CONCAT: {
|
||||
check(b < c); /* at least two operands */
|
||||
break;
|
||||
}
|
||||
case OP_TFORLOOP: {
|
||||
check(c >= 1); /* at least one result (control variable) */
|
||||
checkreg(pt, a+2+c); /* space for results */
|
||||
if (reg >= a+2) last = pc; /* affect all regs above its base */
|
||||
break;
|
||||
}
|
||||
case OP_FORLOOP:
|
||||
case OP_FORPREP:
|
||||
checkreg(pt, a+3);
|
||||
/* go through */
|
||||
case OP_JMP: {
|
||||
int dest = pc+1+b;
|
||||
/* not full check and jump is forward and do not skip `lastpc'? */
|
||||
if (reg != NO_REG && pc < dest && dest <= lastpc)
|
||||
pc += b; /* do the jump */
|
||||
break;
|
||||
}
|
||||
case OP_CALL:
|
||||
case OP_TAILCALL: {
|
||||
if (b != 0) {
|
||||
checkreg(pt, a+b-1);
|
||||
}
|
||||
c--; /* c = num. returns */
|
||||
if (c == LUA_MULTRET) {
|
||||
check(checkopenop(pt, pc));
|
||||
}
|
||||
else if (c != 0)
|
||||
checkreg(pt, a+c-1);
|
||||
if (reg >= a) last = pc; /* affect all registers above base */
|
||||
break;
|
||||
}
|
||||
case OP_RETURN: {
|
||||
b--; /* b = num. returns */
|
||||
if (b > 0) checkreg(pt, a+b-1);
|
||||
break;
|
||||
}
|
||||
case OP_SETLIST: {
|
||||
if (b > 0) checkreg(pt, a + b);
|
||||
if (c == 0) pc++;
|
||||
break;
|
||||
}
|
||||
case OP_CLOSURE: {
|
||||
int nup;
|
||||
check(b < pt->sizep);
|
||||
nup = pt->p[b]->nups;
|
||||
check(pc + nup < pt->sizecode);
|
||||
for (; nup>0; nup--) {
|
||||
OpCode op1 = GET_OPCODE(pt->code[pc+nup]);
|
||||
check(op1 == OP_GETUPVAL || op1 == OP_MOVE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_VARARG: {
|
||||
check((pt->is_vararg & VARARG_ISVARARG) &&
|
||||
!(pt->is_vararg & VARARG_NEEDSARG));
|
||||
b--;
|
||||
if (b == LUA_MULTRET) check(checkopenop(pt, pc));
|
||||
checkreg(pt, a+b-1);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return pt->code[last];
|
||||
}
|
||||
|
||||
#undef check
|
||||
#undef checkjump
|
||||
#undef checkreg
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
int luaG_checkcode (const Proto *pt) {
|
||||
return (symbexec(pt, pt->sizecode, NO_REG) != 0);
|
||||
}
|
||||
|
||||
|
||||
static const char *kname (Proto *p, int c) {
|
||||
if (ISK(c) && ttisstring(&p->k[INDEXK(c)]))
|
||||
return svalue(&p->k[INDEXK(c)]);
|
||||
else
|
||||
return "?";
|
||||
}
|
||||
|
||||
|
||||
static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos,
|
||||
const char **name) {
|
||||
if (isLua(ci)) { /* a Lua function? */
|
||||
Proto *p = ci_func(ci)->l.p;
|
||||
int pc = currentpc(L, ci);
|
||||
Instruction i;
|
||||
*name = luaF_getlocalname(p, stackpos+1, pc);
|
||||
if (*name) /* is a local? */
|
||||
return "local";
|
||||
i = symbexec(p, pc, stackpos); /* try symbolic execution */
|
||||
lua_assert(pc != -1);
|
||||
switch (GET_OPCODE(i)) {
|
||||
case OP_GETGLOBAL: {
|
||||
int g = GETARG_Bx(i); /* global index */
|
||||
lua_assert(ttisstring(&p->k[g]));
|
||||
*name = svalue(&p->k[g]);
|
||||
return "global";
|
||||
}
|
||||
case OP_MOVE: {
|
||||
int a = GETARG_A(i);
|
||||
int b = GETARG_B(i); /* move from `b' to `a' */
|
||||
if (b < a)
|
||||
return getobjname(L, ci, b, name); /* get name for `b' */
|
||||
break;
|
||||
}
|
||||
case OP_GETTABLE: {
|
||||
int k = GETARG_C(i); /* key index */
|
||||
*name = kname(p, k);
|
||||
return "field";
|
||||
}
|
||||
case OP_GETUPVAL: {
|
||||
int u = GETARG_B(i); /* upvalue index */
|
||||
*name = p->upvalues ? getstr(p->upvalues[u]) : "?";
|
||||
return "upvalue";
|
||||
}
|
||||
case OP_SELF: {
|
||||
int k = GETARG_C(i); /* key index */
|
||||
*name = kname(p, k);
|
||||
return "method";
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return NULL; /* no useful name found */
|
||||
}
|
||||
|
||||
|
||||
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
|
||||
Instruction i;
|
||||
if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1))
|
||||
return NULL; /* calling function is not Lua (or is unknown) */
|
||||
ci--; /* calling function */
|
||||
i = ci_func(ci)->l.p->code[currentpc(L, ci)];
|
||||
if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL ||
|
||||
GET_OPCODE(i) == OP_TFORLOOP)
|
||||
return getobjname(L, ci, GETARG_A(i), name);
|
||||
else
|
||||
return NULL; /* no useful name can be found */
|
||||
}
|
||||
|
||||
|
||||
/* only ANSI way to check whether a pointer points to an array */
|
||||
static int isinstack (CallInfo *ci, const TValue *o) {
|
||||
StkId p;
|
||||
for (p = ci->base; p < ci->top; p++)
|
||||
if (o == p) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
|
||||
const char *name = NULL;
|
||||
const char *t = luaT_typenames[ttype(o)];
|
||||
const char *kind = (isinstack(L->ci, o)) ?
|
||||
getobjname(L, L->ci, cast_int(o - L->base), &name) :
|
||||
NULL;
|
||||
if (kind)
|
||||
luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)",
|
||||
op, kind, name, t);
|
||||
else
|
||||
luaG_runerror(L, "attempt to %s a %s value", op, t);
|
||||
}
|
||||
|
||||
|
||||
void luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
|
||||
if (ttisstring(p1)) p1 = p2;
|
||||
lua_assert(!ttisstring(p1));
|
||||
luaG_typeerror(L, p1, "concatenate");
|
||||
}
|
||||
|
||||
|
||||
void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) {
|
||||
TValue temp;
|
||||
if (luaV_tonumber(p1, &temp) == NULL)
|
||||
p2 = p1; /* first operand is wrong */
|
||||
luaG_typeerror(L, p2, "perform arithmetic on");
|
||||
}
|
||||
|
||||
|
||||
int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
|
||||
const char *t1 = luaT_typenames[ttype(p1)];
|
||||
const char *t2 = luaT_typenames[ttype(p2)];
|
||||
if (t1[2] == t2[2])
|
||||
luaG_runerror(L, "attempt to compare two %s values", t1);
|
||||
else
|
||||
luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void addinfo (lua_State *L, const char *msg) {
|
||||
CallInfo *ci = L->ci;
|
||||
if (isLua(ci)) { /* is Lua code? */
|
||||
char buff[LUA_IDSIZE]; /* add file:line information */
|
||||
int line = currentline(L, ci);
|
||||
luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE);
|
||||
luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaG_errormsg (lua_State *L) {
|
||||
if (L->errfunc != 0) { /* is there an error handling function? */
|
||||
StkId errfunc = restorestack(L, L->errfunc);
|
||||
if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR);
|
||||
setobjs2s(L, L->top, L->top - 1); /* move argument */
|
||||
setobjs2s(L, L->top - 1, errfunc); /* push function */
|
||||
incr_top(L);
|
||||
luaD_call(L, L->top - 2, 1); /* call it */
|
||||
}
|
||||
luaD_throw(L, LUA_ERRRUN);
|
||||
}
|
||||
|
||||
|
||||
void luaG_runerror (lua_State *L, const char *fmt, ...) {
|
||||
va_list argp;
|
||||
va_start(argp, fmt);
|
||||
addinfo(L, luaO_pushvfstring(L, fmt, argp));
|
||||
va_end(argp);
|
||||
luaG_errormsg(L);
|
||||
}
|
||||
|
33
src/lua/ldebug.h
Normal file
33
src/lua/ldebug.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
** $Id: ldebug.h,v 2.3 2005/04/25 19:24:10 roberto Exp $
|
||||
** Auxiliary functions from Debug Interface module
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef ldebug_h
|
||||
#define ldebug_h
|
||||
|
||||
|
||||
#include "lstate.h"
|
||||
|
||||
|
||||
#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1)
|
||||
|
||||
#define getline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0)
|
||||
|
||||
#define resethookcount(L) (L->hookcount = L->basehookcount)
|
||||
|
||||
|
||||
LUAI_FUNC void luaG_typeerror (lua_State *L, const TValue *o,
|
||||
const char *opname);
|
||||
LUAI_FUNC void luaG_concaterror (lua_State *L, StkId p1, StkId p2);
|
||||
LUAI_FUNC void luaG_aritherror (lua_State *L, const TValue *p1,
|
||||
const TValue *p2);
|
||||
LUAI_FUNC int luaG_ordererror (lua_State *L, const TValue *p1,
|
||||
const TValue *p2);
|
||||
LUAI_FUNC void luaG_runerror (lua_State *L, const char *fmt, ...);
|
||||
LUAI_FUNC void luaG_errormsg (lua_State *L);
|
||||
LUAI_FUNC int luaG_checkcode (const Proto *pt);
|
||||
LUAI_FUNC int luaG_checkopenop (Instruction i);
|
||||
|
||||
#endif
|
515
src/lua/ldo.c
Normal file
515
src/lua/ldo.c
Normal file
@ -0,0 +1,515 @@
|
||||
/*
|
||||
** $Id: ldo.c,v 2.37 2005/12/22 16:19:56 roberto Exp $
|
||||
** Stack and Call structure of Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ldo_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "ldebug.h"
|
||||
#include "ldo.h"
|
||||
#include "lfunc.h"
|
||||
#include "lgc.h"
|
||||
#include "lmem.h"
|
||||
#include "lobject.h"
|
||||
#include "lopcodes.h"
|
||||
#include "lparser.h"
|
||||
#include "lstate.h"
|
||||
#include "lstring.h"
|
||||
#include "ltable.h"
|
||||
#include "ltm.h"
|
||||
#include "lundump.h"
|
||||
#include "lvm.h"
|
||||
#include "lzio.h"
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Error-recovery functions
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
|
||||
/* chain list of long jump buffers */
|
||||
struct lua_longjmp {
|
||||
struct lua_longjmp *previous;
|
||||
luai_jmpbuf b;
|
||||
volatile int status; /* error code */
|
||||
};
|
||||
|
||||
|
||||
void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
|
||||
switch (errcode) {
|
||||
case LUA_ERRMEM: {
|
||||
setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG));
|
||||
break;
|
||||
}
|
||||
case LUA_ERRERR: {
|
||||
setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
|
||||
break;
|
||||
}
|
||||
case LUA_ERRSYNTAX:
|
||||
case LUA_ERRRUN: {
|
||||
setobjs2s(L, oldtop, L->top - 1); /* error message on current top */
|
||||
break;
|
||||
}
|
||||
}
|
||||
L->top = oldtop + 1;
|
||||
}
|
||||
|
||||
|
||||
static void restore_stack_limit (lua_State *L) {
|
||||
lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1);
|
||||
if (L->size_ci > LUAI_MAXCALLS) { /* there was an overflow? */
|
||||
int inuse = cast_int(L->ci - L->base_ci);
|
||||
if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */
|
||||
luaD_reallocCI(L, LUAI_MAXCALLS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void resetstack (lua_State *L, int status) {
|
||||
L->ci = L->base_ci;
|
||||
L->base = L->ci->base;
|
||||
luaF_close(L, L->base); /* close eventual pending closures */
|
||||
luaD_seterrorobj(L, status, L->base);
|
||||
L->nCcalls = 0;
|
||||
L->allowhook = 1;
|
||||
restore_stack_limit(L);
|
||||
L->errfunc = 0;
|
||||
L->errorJmp = NULL;
|
||||
}
|
||||
|
||||
|
||||
void luaD_throw (lua_State *L, int errcode) {
|
||||
if (L->errorJmp) {
|
||||
L->errorJmp->status = errcode;
|
||||
LUAI_THROW(L, L->errorJmp);
|
||||
}
|
||||
else {
|
||||
L->status = cast_byte(errcode);
|
||||
if (G(L)->panic) {
|
||||
resetstack(L, errcode);
|
||||
lua_unlock(L);
|
||||
G(L)->panic(L);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
|
||||
struct lua_longjmp lj;
|
||||
lj.status = 0;
|
||||
lj.previous = L->errorJmp; /* chain new error handler */
|
||||
L->errorJmp = &lj;
|
||||
LUAI_TRY(L, &lj,
|
||||
(*f)(L, ud);
|
||||
);
|
||||
L->errorJmp = lj.previous; /* restore old error handler */
|
||||
return lj.status;
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
static void correctstack (lua_State *L, TValue *oldstack) {
|
||||
CallInfo *ci;
|
||||
GCObject *up;
|
||||
L->top = (L->top - oldstack) + L->stack;
|
||||
for (up = L->openupval; up != NULL; up = up->gch.next)
|
||||
gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;
|
||||
for (ci = L->base_ci; ci <= L->ci; ci++) {
|
||||
ci->top = (ci->top - oldstack) + L->stack;
|
||||
ci->base = (ci->base - oldstack) + L->stack;
|
||||
ci->func = (ci->func - oldstack) + L->stack;
|
||||
}
|
||||
L->base = (L->base - oldstack) + L->stack;
|
||||
}
|
||||
|
||||
|
||||
void luaD_reallocstack (lua_State *L, int newsize) {
|
||||
TValue *oldstack = L->stack;
|
||||
int realsize = newsize + 1 + EXTRA_STACK;
|
||||
lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1);
|
||||
luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue);
|
||||
L->stacksize = realsize;
|
||||
L->stack_last = L->stack+newsize;
|
||||
correctstack(L, oldstack);
|
||||
}
|
||||
|
||||
|
||||
void luaD_reallocCI (lua_State *L, int newsize) {
|
||||
CallInfo *oldci = L->base_ci;
|
||||
luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo);
|
||||
L->size_ci = newsize;
|
||||
L->ci = (L->ci - oldci) + L->base_ci;
|
||||
L->end_ci = L->base_ci + L->size_ci - 1;
|
||||
}
|
||||
|
||||
|
||||
void luaD_growstack (lua_State *L, int n) {
|
||||
if (n <= L->stacksize) /* double size is enough? */
|
||||
luaD_reallocstack(L, 2*L->stacksize);
|
||||
else
|
||||
luaD_reallocstack(L, L->stacksize + n);
|
||||
}
|
||||
|
||||
|
||||
static CallInfo *growCI (lua_State *L) {
|
||||
if (L->size_ci > LUAI_MAXCALLS) /* overflow while handling overflow? */
|
||||
luaD_throw(L, LUA_ERRERR);
|
||||
else {
|
||||
luaD_reallocCI(L, 2*L->size_ci);
|
||||
if (L->size_ci > LUAI_MAXCALLS)
|
||||
luaG_runerror(L, "stack overflow");
|
||||
}
|
||||
return ++L->ci;
|
||||
}
|
||||
|
||||
|
||||
void luaD_callhook (lua_State *L, int event, int line) {
|
||||
lua_Hook hook = L->hook;
|
||||
if (hook && L->allowhook) {
|
||||
ptrdiff_t top = savestack(L, L->top);
|
||||
ptrdiff_t ci_top = savestack(L, L->ci->top);
|
||||
lua_Debug ar;
|
||||
ar.event = event;
|
||||
ar.currentline = line;
|
||||
if (event == LUA_HOOKTAILRET)
|
||||
ar.i_ci = 0; /* tail call; no debug information about it */
|
||||
else
|
||||
ar.i_ci = cast_int(L->ci - L->base_ci);
|
||||
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
|
||||
L->ci->top = L->top + LUA_MINSTACK;
|
||||
lua_assert(L->ci->top <= L->stack_last);
|
||||
L->allowhook = 0; /* cannot call hooks inside a hook */
|
||||
lua_unlock(L);
|
||||
(*hook)(L, &ar);
|
||||
lua_lock(L);
|
||||
lua_assert(!L->allowhook);
|
||||
L->allowhook = 1;
|
||||
L->ci->top = restorestack(L, ci_top);
|
||||
L->top = restorestack(L, top);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
|
||||
int i;
|
||||
int nfixargs = p->numparams;
|
||||
Table *htab = NULL;
|
||||
StkId base, fixed;
|
||||
for (; actual < nfixargs; ++actual)
|
||||
setnilvalue(L->top++);
|
||||
#if defined(LUA_COMPAT_VARARG)
|
||||
if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */
|
||||
int nvar = actual - nfixargs; /* number of extra arguments */
|
||||
lua_assert(p->is_vararg & VARARG_HASARG);
|
||||
luaC_checkGC(L);
|
||||
htab = luaH_new(L, nvar, 1); /* create `arg' table */
|
||||
for (i=0; i<nvar; i++) /* put extra arguments into `arg' table */
|
||||
setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i);
|
||||
/* store counter in field `n' */
|
||||
setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar));
|
||||
}
|
||||
#endif
|
||||
/* move fixed parameters to final position */
|
||||
fixed = L->top - actual; /* first fixed argument */
|
||||
base = L->top; /* final position of first argument */
|
||||
for (i=0; i<nfixargs; i++) {
|
||||
setobjs2s(L, L->top++, fixed+i);
|
||||
setnilvalue(fixed+i);
|
||||
}
|
||||
/* add `arg' parameter */
|
||||
if (htab) {
|
||||
sethvalue(L, L->top++, htab);
|
||||
lua_assert(iswhite(obj2gco(htab)));
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
|
||||
static StkId tryfuncTM (lua_State *L, StkId func) {
|
||||
const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL);
|
||||
StkId p;
|
||||
ptrdiff_t funcr = savestack(L, func);
|
||||
if (!ttisfunction(tm))
|
||||
luaG_typeerror(L, func, "call");
|
||||
/* Open a hole inside the stack at `func' */
|
||||
for (p = L->top; p > func; p--) setobjs2s(L, p, p-1);
|
||||
incr_top(L);
|
||||
func = restorestack(L, funcr); /* previous call may change stack */
|
||||
setobj2s(L, func, tm); /* tag method is the new function to be called */
|
||||
return func;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define inc_ci(L) \
|
||||
((L->ci == L->end_ci) ? growCI(L) : \
|
||||
(condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci))
|
||||
|
||||
|
||||
int luaD_precall (lua_State *L, StkId func, int nresults) {
|
||||
LClosure *cl;
|
||||
ptrdiff_t funcr;
|
||||
if (!ttisfunction(func)) /* `func' is not a function? */
|
||||
func = tryfuncTM(L, func); /* check the `function' tag method */
|
||||
funcr = savestack(L, func);
|
||||
cl = &clvalue(func)->l;
|
||||
L->ci->savedpc = L->savedpc;
|
||||
if (!cl->isC) { /* Lua function? prepare its call */
|
||||
CallInfo *ci;
|
||||
StkId st, base;
|
||||
Proto *p = cl->p;
|
||||
luaD_checkstack(L, p->maxstacksize);
|
||||
func = restorestack(L, funcr);
|
||||
if (!p->is_vararg) { /* no varargs? */
|
||||
base = func + 1;
|
||||
if (L->top > base + p->numparams)
|
||||
L->top = base + p->numparams;
|
||||
}
|
||||
else { /* vararg function */
|
||||
int nargs = cast_int(L->top - func) - 1;
|
||||
base = adjust_varargs(L, p, nargs);
|
||||
func = restorestack(L, funcr); /* previous call may change the stack */
|
||||
}
|
||||
ci = inc_ci(L); /* now `enter' new function */
|
||||
ci->func = func;
|
||||
L->base = ci->base = base;
|
||||
ci->top = L->base + p->maxstacksize;
|
||||
lua_assert(ci->top <= L->stack_last);
|
||||
L->savedpc = p->code; /* starting point */
|
||||
ci->tailcalls = 0;
|
||||
ci->nresults = nresults;
|
||||
for (st = L->top; st < ci->top; st++)
|
||||
setnilvalue(st);
|
||||
L->top = ci->top;
|
||||
if (L->hookmask & LUA_MASKCALL) {
|
||||
L->savedpc++; /* hooks assume 'pc' is already incremented */
|
||||
luaD_callhook(L, LUA_HOOKCALL, -1);
|
||||
L->savedpc--; /* correct 'pc' */
|
||||
}
|
||||
return PCRLUA;
|
||||
}
|
||||
else { /* if is a C function, call it */
|
||||
CallInfo *ci;
|
||||
int n;
|
||||
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
|
||||
ci = inc_ci(L); /* now `enter' new function */
|
||||
ci->func = restorestack(L, funcr);
|
||||
L->base = ci->base = ci->func + 1;
|
||||
ci->top = L->top + LUA_MINSTACK;
|
||||
lua_assert(ci->top <= L->stack_last);
|
||||
ci->nresults = nresults;
|
||||
if (L->hookmask & LUA_MASKCALL)
|
||||
luaD_callhook(L, LUA_HOOKCALL, -1);
|
||||
lua_unlock(L);
|
||||
n = (*curr_func(L)->c.f)(L); /* do the actual call */
|
||||
lua_lock(L);
|
||||
if (n < 0) /* yielding? */
|
||||
return PCRYIELD;
|
||||
else {
|
||||
luaD_poscall(L, L->top - n);
|
||||
return PCRC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static StkId callrethooks (lua_State *L, StkId firstResult) {
|
||||
ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */
|
||||
luaD_callhook(L, LUA_HOOKRET, -1);
|
||||
if (f_isLua(L->ci)) { /* Lua function? */
|
||||
while (L->ci->tailcalls--) /* call hook for eventual tail calls */
|
||||
luaD_callhook(L, LUA_HOOKTAILRET, -1);
|
||||
}
|
||||
return restorestack(L, fr);
|
||||
}
|
||||
|
||||
|
||||
int luaD_poscall (lua_State *L, StkId firstResult) {
|
||||
StkId res;
|
||||
int wanted, i;
|
||||
CallInfo *ci;
|
||||
if (L->hookmask & LUA_MASKRET)
|
||||
firstResult = callrethooks(L, firstResult);
|
||||
ci = L->ci--;
|
||||
res = ci->func; /* res == final position of 1st result */
|
||||
wanted = ci->nresults;
|
||||
L->base = (ci - 1)->base; /* restore base */
|
||||
L->savedpc = (ci - 1)->savedpc; /* restore savedpc */
|
||||
/* move results to correct place */
|
||||
for (i = wanted; i != 0 && firstResult < L->top; i--)
|
||||
setobjs2s(L, res++, firstResult++);
|
||||
while (i-- > 0)
|
||||
setnilvalue(res++);
|
||||
L->top = res;
|
||||
return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Call a function (C or Lua). The function to be called is at *func.
|
||||
** The arguments are on the stack, right after the function.
|
||||
** When returns, all the results are on the stack, starting at the original
|
||||
** function position.
|
||||
*/
|
||||
void luaD_call (lua_State *L, StkId func, int nResults) {
|
||||
if (++L->nCcalls >= LUAI_MAXCCALLS) {
|
||||
if (L->nCcalls == LUAI_MAXCCALLS)
|
||||
luaG_runerror(L, "C stack overflow");
|
||||
else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
|
||||
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
|
||||
}
|
||||
if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */
|
||||
luaV_execute(L, 1); /* call it */
|
||||
L->nCcalls--;
|
||||
luaC_checkGC(L);
|
||||
}
|
||||
|
||||
|
||||
static void resume (lua_State *L, void *ud) {
|
||||
StkId firstArg = cast(StkId, ud);
|
||||
CallInfo *ci = L->ci;
|
||||
if (L->status != LUA_YIELD) { /* start coroutine */
|
||||
lua_assert(ci == L->base_ci && firstArg > L->base);
|
||||
if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA)
|
||||
return;
|
||||
}
|
||||
else { /* resuming from previous yield */
|
||||
if (!f_isLua(ci)) { /* `common' yield? */
|
||||
/* finish interrupted execution of `OP_CALL' */
|
||||
lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL ||
|
||||
GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL);
|
||||
if (luaD_poscall(L, firstArg)) /* complete it... */
|
||||
L->top = L->ci->top; /* and correct top if not multiple results */
|
||||
}
|
||||
else /* yielded inside a hook: just continue its execution */
|
||||
L->base = L->ci->base;
|
||||
}
|
||||
L->status = 0;
|
||||
luaV_execute(L, cast_int(L->ci - L->base_ci));
|
||||
}
|
||||
|
||||
|
||||
static int resume_error (lua_State *L, const char *msg) {
|
||||
L->top = L->ci->base;
|
||||
setsvalue2s(L, L->top, luaS_new(L, msg));
|
||||
incr_top(L);
|
||||
lua_unlock(L);
|
||||
return LUA_ERRRUN;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_resume (lua_State *L, int nargs) {
|
||||
int status;
|
||||
lua_lock(L);
|
||||
if (L->status != LUA_YIELD) {
|
||||
if (L->status != 0)
|
||||
return resume_error(L, "cannot resume dead coroutine");
|
||||
else if (L->ci != L->base_ci)
|
||||
return resume_error(L, "cannot resume non-suspended coroutine");
|
||||
}
|
||||
luai_userstateresume(L, nargs);
|
||||
lua_assert(L->errfunc == 0 && L->nCcalls == 0);
|
||||
status = luaD_rawrunprotected(L, resume, L->top - nargs);
|
||||
if (status != 0) { /* error? */
|
||||
L->status = cast_byte(status); /* mark thread as `dead' */
|
||||
luaD_seterrorobj(L, status, L->top);
|
||||
L->ci->top = L->top;
|
||||
}
|
||||
else
|
||||
status = L->status;
|
||||
lua_unlock(L);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_yield (lua_State *L, int nresults) {
|
||||
luai_userstateyield(L, nresults);
|
||||
lua_lock(L);
|
||||
if (L->nCcalls > 0)
|
||||
luaG_runerror(L, "attempt to yield across metamethod/C-call boundary");
|
||||
L->base = L->top - nresults; /* protect stack slots below */
|
||||
L->status = LUA_YIELD;
|
||||
lua_unlock(L);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int luaD_pcall (lua_State *L, Pfunc func, void *u,
|
||||
ptrdiff_t old_top, ptrdiff_t ef) {
|
||||
int status;
|
||||
unsigned short oldnCcalls = L->nCcalls;
|
||||
ptrdiff_t old_ci = saveci(L, L->ci);
|
||||
lu_byte old_allowhooks = L->allowhook;
|
||||
ptrdiff_t old_errfunc = L->errfunc;
|
||||
L->errfunc = ef;
|
||||
status = luaD_rawrunprotected(L, func, u);
|
||||
if (status != 0) { /* an error occurred? */
|
||||
StkId oldtop = restorestack(L, old_top);
|
||||
luaF_close(L, oldtop); /* close eventual pending closures */
|
||||
luaD_seterrorobj(L, status, oldtop);
|
||||
L->nCcalls = oldnCcalls;
|
||||
L->ci = restoreci(L, old_ci);
|
||||
L->base = L->ci->base;
|
||||
L->savedpc = L->ci->savedpc;
|
||||
L->allowhook = old_allowhooks;
|
||||
restore_stack_limit(L);
|
||||
}
|
||||
L->errfunc = old_errfunc;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Execute a protected parser.
|
||||
*/
|
||||
struct SParser { /* data to `f_parser' */
|
||||
ZIO *z;
|
||||
Mbuffer buff; /* buffer to be used by the scanner */
|
||||
const char *name;
|
||||
};
|
||||
|
||||
static void f_parser (lua_State *L, void *ud) {
|
||||
int i;
|
||||
Proto *tf;
|
||||
Closure *cl;
|
||||
struct SParser *p = cast(struct SParser *, ud);
|
||||
int c = luaZ_lookahead(p->z);
|
||||
luaC_checkGC(L);
|
||||
tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z,
|
||||
&p->buff, p->name);
|
||||
cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L)));
|
||||
cl->l.p = tf;
|
||||
for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */
|
||||
cl->l.upvals[i] = luaF_newupval(L);
|
||||
setclvalue(L, L->top, cl);
|
||||
incr_top(L);
|
||||
}
|
||||
|
||||
|
||||
int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) {
|
||||
struct SParser p;
|
||||
int status;
|
||||
p.z = z; p.name = name;
|
||||
luaZ_initbuffer(L, &p.buff);
|
||||
status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
|
||||
luaZ_freebuffer(L, &p.buff);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
57
src/lua/ldo.h
Normal file
57
src/lua/ldo.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
** $Id: ldo.h,v 2.7 2005/08/24 16:15:49 roberto Exp $
|
||||
** Stack and Call structure of Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef ldo_h
|
||||
#define ldo_h
|
||||
|
||||
|
||||
#include "lobject.h"
|
||||
#include "lstate.h"
|
||||
#include "lzio.h"
|
||||
|
||||
|
||||
#define luaD_checkstack(L,n) \
|
||||
if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \
|
||||
luaD_growstack(L, n); \
|
||||
else condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1));
|
||||
|
||||
|
||||
#define incr_top(L) {luaD_checkstack(L,1); L->top++;}
|
||||
|
||||
#define savestack(L,p) ((char *)(p) - (char *)L->stack)
|
||||
#define restorestack(L,n) ((TValue *)((char *)L->stack + (n)))
|
||||
|
||||
#define saveci(L,p) ((char *)(p) - (char *)L->base_ci)
|
||||
#define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n)))
|
||||
|
||||
|
||||
/* results from luaD_precall */
|
||||
#define PCRLUA 0 /* initiated a call to a Lua function */
|
||||
#define PCRC 1 /* did a call to a C function */
|
||||
#define PCRYIELD 2 /* C funtion yielded */
|
||||
|
||||
|
||||
/* type of protected functions, to be ran by `runprotected' */
|
||||
typedef void (*Pfunc) (lua_State *L, void *ud);
|
||||
|
||||
LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name);
|
||||
LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line);
|
||||
LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults);
|
||||
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
|
||||
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
|
||||
ptrdiff_t oldtop, ptrdiff_t ef);
|
||||
LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult);
|
||||
LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize);
|
||||
LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
|
||||
LUAI_FUNC void luaD_growstack (lua_State *L, int n);
|
||||
|
||||
LUAI_FUNC void luaD_throw (lua_State *L, int errcode);
|
||||
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
|
||||
|
||||
LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop);
|
||||
|
||||
#endif
|
||||
|
164
src/lua/ldump.c
Normal file
164
src/lua/ldump.c
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
** $Id: ldump.c,v 1.15 2006/02/16 15:53:49 lhf Exp $
|
||||
** save precompiled Lua chunks
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define ldump_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lobject.h"
|
||||
#include "lstate.h"
|
||||
#include "lundump.h"
|
||||
|
||||
typedef struct {
|
||||
lua_State* L;
|
||||
lua_Writer writer;
|
||||
void* data;
|
||||
int strip;
|
||||
int status;
|
||||
} DumpState;
|
||||
|
||||
#define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D)
|
||||
#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D)
|
||||
|
||||
static void DumpBlock(const void* b, size_t size, DumpState* D)
|
||||
{
|
||||
if (D->status==0)
|
||||
{
|
||||
lua_unlock(D->L);
|
||||
D->status=(*D->writer)(D->L,b,size,D->data);
|
||||
lua_lock(D->L);
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpChar(int y, DumpState* D)
|
||||
{
|
||||
char x=(char)y;
|
||||
DumpVar(x,D);
|
||||
}
|
||||
|
||||
static void DumpInt(int x, DumpState* D)
|
||||
{
|
||||
DumpVar(x,D);
|
||||
}
|
||||
|
||||
static void DumpNumber(lua_Number x, DumpState* D)
|
||||
{
|
||||
DumpVar(x,D);
|
||||
}
|
||||
|
||||
static void DumpVector(const void* b, int n, size_t size, DumpState* D)
|
||||
{
|
||||
DumpInt(n,D);
|
||||
DumpMem(b,n,size,D);
|
||||
}
|
||||
|
||||
static void DumpString(const TString* s, DumpState* D)
|
||||
{
|
||||
if (s==NULL || getstr(s)==NULL)
|
||||
{
|
||||
size_t size=0;
|
||||
DumpVar(size,D);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t size=s->tsv.len+1; /* include trailing '\0' */
|
||||
DumpVar(size,D);
|
||||
DumpBlock(getstr(s),size,D);
|
||||
}
|
||||
}
|
||||
|
||||
#define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D)
|
||||
|
||||
static void DumpFunction(const Proto* f, const TString* p, DumpState* D);
|
||||
|
||||
static void DumpConstants(const Proto* f, DumpState* D)
|
||||
{
|
||||
int i,n=f->sizek;
|
||||
DumpInt(n,D);
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
const TValue* o=&f->k[i];
|
||||
DumpChar(ttype(o),D);
|
||||
switch (ttype(o))
|
||||
{
|
||||
case LUA_TNIL:
|
||||
break;
|
||||
case LUA_TBOOLEAN:
|
||||
DumpChar(bvalue(o),D);
|
||||
break;
|
||||
case LUA_TNUMBER:
|
||||
DumpNumber(nvalue(o),D);
|
||||
break;
|
||||
case LUA_TSTRING:
|
||||
DumpString(rawtsvalue(o),D);
|
||||
break;
|
||||
default:
|
||||
lua_assert(0); /* cannot happen */
|
||||
break;
|
||||
}
|
||||
}
|
||||
n=f->sizep;
|
||||
DumpInt(n,D);
|
||||
for (i=0; i<n; i++) DumpFunction(f->p[i],f->source,D);
|
||||
}
|
||||
|
||||
static void DumpDebug(const Proto* f, DumpState* D)
|
||||
{
|
||||
int i,n;
|
||||
n= (D->strip) ? 0 : f->sizelineinfo;
|
||||
DumpVector(f->lineinfo,n,sizeof(int),D);
|
||||
n= (D->strip) ? 0 : f->sizelocvars;
|
||||
DumpInt(n,D);
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
DumpString(f->locvars[i].varname,D);
|
||||
DumpInt(f->locvars[i].startpc,D);
|
||||
DumpInt(f->locvars[i].endpc,D);
|
||||
}
|
||||
n= (D->strip) ? 0 : f->sizeupvalues;
|
||||
DumpInt(n,D);
|
||||
for (i=0; i<n; i++) DumpString(f->upvalues[i],D);
|
||||
}
|
||||
|
||||
static void DumpFunction(const Proto* f, const TString* p, DumpState* D)
|
||||
{
|
||||
DumpString((f->source==p || D->strip) ? NULL : f->source,D);
|
||||
DumpInt(f->linedefined,D);
|
||||
DumpInt(f->lastlinedefined,D);
|
||||
DumpChar(f->nups,D);
|
||||
DumpChar(f->numparams,D);
|
||||
DumpChar(f->is_vararg,D);
|
||||
DumpChar(f->maxstacksize,D);
|
||||
DumpCode(f,D);
|
||||
DumpConstants(f,D);
|
||||
DumpDebug(f,D);
|
||||
}
|
||||
|
||||
static void DumpHeader(DumpState* D)
|
||||
{
|
||||
char h[LUAC_HEADERSIZE];
|
||||
luaU_header(h);
|
||||
DumpBlock(h,LUAC_HEADERSIZE,D);
|
||||
}
|
||||
|
||||
/*
|
||||
** dump Lua function as precompiled chunk
|
||||
*/
|
||||
int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
|
||||
{
|
||||
DumpState D;
|
||||
D.L=L;
|
||||
D.writer=w;
|
||||
D.data=data;
|
||||
D.strip=strip;
|
||||
D.status=0;
|
||||
DumpHeader(&D);
|
||||
DumpFunction(f,NULL,&D);
|
||||
return D.status;
|
||||
}
|
174
src/lua/lfunc.c
Normal file
174
src/lua/lfunc.c
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
** $Id: lfunc.c,v 2.12 2005/12/22 16:19:56 roberto Exp $
|
||||
** Auxiliary functions to manipulate prototypes and closures
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define lfunc_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lfunc.h"
|
||||
#include "lgc.h"
|
||||
#include "lmem.h"
|
||||
#include "lobject.h"
|
||||
#include "lstate.h"
|
||||
|
||||
|
||||
|
||||
Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) {
|
||||
Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems)));
|
||||
luaC_link(L, obj2gco(c), LUA_TFUNCTION);
|
||||
c->c.isC = 1;
|
||||
c->c.env = e;
|
||||
c->c.nupvalues = cast_byte(nelems);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) {
|
||||
Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems)));
|
||||
luaC_link(L, obj2gco(c), LUA_TFUNCTION);
|
||||
c->l.isC = 0;
|
||||
c->l.env = e;
|
||||
c->l.nupvalues = cast_byte(nelems);
|
||||
while (nelems--) c->l.upvals[nelems] = NULL;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
UpVal *luaF_newupval (lua_State *L) {
|
||||
UpVal *uv = luaM_new(L, UpVal);
|
||||
luaC_link(L, obj2gco(uv), LUA_TUPVAL);
|
||||
uv->v = &uv->u.value;
|
||||
setnilvalue(uv->v);
|
||||
return uv;
|
||||
}
|
||||
|
||||
|
||||
UpVal *luaF_findupval (lua_State *L, StkId level) {
|
||||
global_State *g = G(L);
|
||||
GCObject **pp = &L->openupval;
|
||||
UpVal *p;
|
||||
UpVal *uv;
|
||||
while ((p = ngcotouv(*pp)) != NULL && p->v >= level) {
|
||||
lua_assert(p->v != &p->u.value);
|
||||
if (p->v == level) { /* found a corresponding upvalue? */
|
||||
if (isdead(g, obj2gco(p))) /* is it dead? */
|
||||
changewhite(obj2gco(p)); /* ressurect it */
|
||||
return p;
|
||||
}
|
||||
pp = &p->next;
|
||||
}
|
||||
uv = luaM_new(L, UpVal); /* not found: create a new one */
|
||||
uv->tt = LUA_TUPVAL;
|
||||
uv->marked = luaC_white(g);
|
||||
uv->v = level; /* current value lives in the stack */
|
||||
uv->next = *pp; /* chain it in the proper position */
|
||||
*pp = obj2gco(uv);
|
||||
uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */
|
||||
uv->u.l.next = g->uvhead.u.l.next;
|
||||
uv->u.l.next->u.l.prev = uv;
|
||||
g->uvhead.u.l.next = uv;
|
||||
lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
|
||||
return uv;
|
||||
}
|
||||
|
||||
|
||||
static void unlinkupval (UpVal *uv) {
|
||||
lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
|
||||
uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */
|
||||
uv->u.l.prev->u.l.next = uv->u.l.next;
|
||||
}
|
||||
|
||||
|
||||
void luaF_freeupval (lua_State *L, UpVal *uv) {
|
||||
if (uv->v != &uv->u.value) /* is it open? */
|
||||
unlinkupval(uv); /* remove from open list */
|
||||
luaM_free(L, uv); /* free upvalue */
|
||||
}
|
||||
|
||||
|
||||
void luaF_close (lua_State *L, StkId level) {
|
||||
UpVal *uv;
|
||||
global_State *g = G(L);
|
||||
while ((uv = ngcotouv(L->openupval)) != NULL && uv->v >= level) {
|
||||
GCObject *o = obj2gco(uv);
|
||||
lua_assert(!isblack(o) && uv->v != &uv->u.value);
|
||||
L->openupval = uv->next; /* remove from `open' list */
|
||||
if (isdead(g, o))
|
||||
luaF_freeupval(L, uv); /* free upvalue */
|
||||
else {
|
||||
unlinkupval(uv);
|
||||
setobj(L, &uv->u.value, uv->v);
|
||||
uv->v = &uv->u.value; /* now current value lives here */
|
||||
luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Proto *luaF_newproto (lua_State *L) {
|
||||
Proto *f = luaM_new(L, Proto);
|
||||
luaC_link(L, obj2gco(f), LUA_TPROTO);
|
||||
f->k = NULL;
|
||||
f->sizek = 0;
|
||||
f->p = NULL;
|
||||
f->sizep = 0;
|
||||
f->code = NULL;
|
||||
f->sizecode = 0;
|
||||
f->sizelineinfo = 0;
|
||||
f->sizeupvalues = 0;
|
||||
f->nups = 0;
|
||||
f->upvalues = NULL;
|
||||
f->numparams = 0;
|
||||
f->is_vararg = 0;
|
||||
f->maxstacksize = 0;
|
||||
f->lineinfo = NULL;
|
||||
f->sizelocvars = 0;
|
||||
f->locvars = NULL;
|
||||
f->linedefined = 0;
|
||||
f->lastlinedefined = 0;
|
||||
f->source = NULL;
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
void luaF_freeproto (lua_State *L, Proto *f) {
|
||||
luaM_freearray(L, f->code, f->sizecode, Instruction);
|
||||
luaM_freearray(L, f->p, f->sizep, Proto *);
|
||||
luaM_freearray(L, f->k, f->sizek, TValue);
|
||||
luaM_freearray(L, f->lineinfo, f->sizelineinfo, int);
|
||||
luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar);
|
||||
luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *);
|
||||
luaM_free(L, f);
|
||||
}
|
||||
|
||||
|
||||
void luaF_freeclosure (lua_State *L, Closure *c) {
|
||||
int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) :
|
||||
sizeLclosure(c->l.nupvalues);
|
||||
luaM_freemem(L, c, size);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Look for n-th local variable at line `line' in function `func'.
|
||||
** Returns NULL if not found.
|
||||
*/
|
||||
const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
|
||||
int i;
|
||||
for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
|
||||
if (pc < f->locvars[i].endpc) { /* is variable active? */
|
||||
local_number--;
|
||||
if (local_number == 0)
|
||||
return getstr(f->locvars[i].varname);
|
||||
}
|
||||
}
|
||||
return NULL; /* not found */
|
||||
}
|
||||
|
34
src/lua/lfunc.h
Normal file
34
src/lua/lfunc.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
** $Id: lfunc.h,v 2.4 2005/04/25 19:24:10 roberto Exp $
|
||||
** Auxiliary functions to manipulate prototypes and closures
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef lfunc_h
|
||||
#define lfunc_h
|
||||
|
||||
|
||||
#include "lobject.h"
|
||||
|
||||
|
||||
#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \
|
||||
cast(int, sizeof(TValue)*((n)-1)))
|
||||
|
||||
#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \
|
||||
cast(int, sizeof(TValue *)*((n)-1)))
|
||||
|
||||
|
||||
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
|
||||
LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e);
|
||||
LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e);
|
||||
LUAI_FUNC UpVal *luaF_newupval (lua_State *L);
|
||||
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
|
||||
LUAI_FUNC void luaF_close (lua_State *L, StkId level);
|
||||
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
|
||||
LUAI_FUNC void luaF_freeclosure (lua_State *L, Closure *c);
|
||||
LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv);
|
||||
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
|
||||
int pc);
|
||||
|
||||
|
||||
#endif
|
707
src/lua/lgc.c
Normal file
707
src/lua/lgc.c
Normal file
@ -0,0 +1,707 @@
|
||||
/*
|
||||
** $Id: lgc.c,v 2.37 2005/12/22 16:19:56 roberto Exp $
|
||||
** Garbage Collector
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define lgc_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "ldebug.h"
|
||||
#include "ldo.h"
|
||||
#include "lfunc.h"
|
||||
#include "lgc.h"
|
||||
#include "lmem.h"
|
||||
#include "lobject.h"
|
||||
#include "lstate.h"
|
||||
#include "lstring.h"
|
||||
#include "ltable.h"
|
||||
#include "ltm.h"
|
||||
|
||||
|
||||
#define GCSTEPSIZE 1024u
|
||||
#define GCSWEEPMAX 40
|
||||
#define GCSWEEPCOST 10
|
||||
#define GCFINALIZECOST 100
|
||||
|
||||
|
||||
#define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS))
|
||||
|
||||
#define makewhite(g,x) \
|
||||
((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g)))
|
||||
|
||||
#define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT)
|
||||
#define black2gray(x) resetbit((x)->gch.marked, BLACKBIT)
|
||||
|
||||
#define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT)
|
||||
|
||||
|
||||
#define isfinalized(u) testbit((u)->marked, FINALIZEDBIT)
|
||||
#define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT)
|
||||
|
||||
|
||||
#define KEYWEAK bitmask(KEYWEAKBIT)
|
||||
#define VALUEWEAK bitmask(VALUEWEAKBIT)
|
||||
|
||||
|
||||
|
||||
#define markvalue(g,o) { checkconsistency(o); \
|
||||
if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); }
|
||||
|
||||
#define markobject(g,t) { if (iswhite(obj2gco(t))) \
|
||||
reallymarkobject(g, obj2gco(t)); }
|
||||
|
||||
|
||||
#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause)
|
||||
|
||||
|
||||
static void removeentry (Node *n) {
|
||||
lua_assert(ttisnil(gval(n)));
|
||||
if (iscollectable(gkey(n)))
|
||||
setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */
|
||||
}
|
||||
|
||||
|
||||
static void reallymarkobject (global_State *g, GCObject *o) {
|
||||
lua_assert(iswhite(o) && !isdead(g, o));
|
||||
white2gray(o);
|
||||
switch (o->gch.tt) {
|
||||
case LUA_TSTRING: {
|
||||
return;
|
||||
}
|
||||
case LUA_TUSERDATA: {
|
||||
Table *mt = gco2u(o)->metatable;
|
||||
gray2black(o); /* udata are never gray */
|
||||
if (mt) markobject(g, mt);
|
||||
markobject(g, gco2u(o)->env);
|
||||
return;
|
||||
}
|
||||
case LUA_TUPVAL: {
|
||||
UpVal *uv = gco2uv(o);
|
||||
markvalue(g, uv->v);
|
||||
if (uv->v == &uv->u.value) /* closed? */
|
||||
gray2black(o); /* open upvalues are never black */
|
||||
return;
|
||||
}
|
||||
case LUA_TFUNCTION: {
|
||||
gco2cl(o)->c.gclist = g->gray;
|
||||
g->gray = o;
|
||||
break;
|
||||
}
|
||||
case LUA_TTABLE: {
|
||||
gco2h(o)->gclist = g->gray;
|
||||
g->gray = o;
|
||||
break;
|
||||
}
|
||||
case LUA_TTHREAD: {
|
||||
gco2th(o)->gclist = g->gray;
|
||||
g->gray = o;
|
||||
break;
|
||||
}
|
||||
case LUA_TPROTO: {
|
||||
gco2p(o)->gclist = g->gray;
|
||||
g->gray = o;
|
||||
break;
|
||||
}
|
||||
default: lua_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void marktmu (global_State *g) {
|
||||
GCObject *u = g->tmudata;
|
||||
if (u) {
|
||||
do {
|
||||
u = u->gch.next;
|
||||
makewhite(g, u); /* may be marked, if left from previous GC */
|
||||
reallymarkobject(g, u);
|
||||
} while (u != g->tmudata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* move `dead' udata that need finalization to list `tmudata' */
|
||||
size_t luaC_separateudata (lua_State *L, int all) {
|
||||
global_State *g = G(L);
|
||||
size_t deadmem = 0;
|
||||
GCObject **p = &g->mainthread->next;
|
||||
GCObject *curr;
|
||||
while ((curr = *p) != NULL) {
|
||||
if (!(iswhite(curr) || all) || isfinalized(gco2u(curr)))
|
||||
p = &curr->gch.next; /* don't bother with them */
|
||||
else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) {
|
||||
markfinalized(gco2u(curr)); /* don't need finalization */
|
||||
p = &curr->gch.next;
|
||||
}
|
||||
else { /* must call its gc method */
|
||||
deadmem += sizeudata(gco2u(curr));
|
||||
markfinalized(gco2u(curr));
|
||||
*p = curr->gch.next;
|
||||
/* link `curr' at the end of `tmudata' list */
|
||||
if (g->tmudata == NULL) /* list is empty? */
|
||||
g->tmudata = curr->gch.next = curr; /* creates a circular list */
|
||||
else {
|
||||
curr->gch.next = g->tmudata->gch.next;
|
||||
g->tmudata->gch.next = curr;
|
||||
g->tmudata = curr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return deadmem;
|
||||
}
|
||||
|
||||
|
||||
static int traversetable (global_State *g, Table *h) {
|
||||
int i;
|
||||
int weakkey = 0;
|
||||
int weakvalue = 0;
|
||||
const TValue *mode;
|
||||
if (h->metatable)
|
||||
markobject(g, h->metatable);
|
||||
mode = gfasttm(g, h->metatable, TM_MODE);
|
||||
if (mode && ttisstring(mode)) { /* is there a weak mode? */
|
||||
weakkey = (strchr(svalue(mode), 'k') != NULL);
|
||||
weakvalue = (strchr(svalue(mode), 'v') != NULL);
|
||||
if (weakkey || weakvalue) { /* is really weak? */
|
||||
h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */
|
||||
h->marked |= cast_byte((weakkey << KEYWEAKBIT) |
|
||||
(weakvalue << VALUEWEAKBIT));
|
||||
h->gclist = g->weak; /* must be cleared after GC, ... */
|
||||
g->weak = obj2gco(h); /* ... so put in the appropriate list */
|
||||
}
|
||||
}
|
||||
if (weakkey && weakvalue) return 1;
|
||||
if (!weakvalue) {
|
||||
i = h->sizearray;
|
||||
while (i--)
|
||||
markvalue(g, &h->array[i]);
|
||||
}
|
||||
i = sizenode(h);
|
||||
while (i--) {
|
||||
Node *n = gnode(h, i);
|
||||
lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n)));
|
||||
if (ttisnil(gval(n)))
|
||||
removeentry(n); /* remove empty entries */
|
||||
else {
|
||||
lua_assert(!ttisnil(gkey(n)));
|
||||
if (!weakkey) markvalue(g, gkey(n));
|
||||
if (!weakvalue) markvalue(g, gval(n));
|
||||
}
|
||||
}
|
||||
return weakkey || weakvalue;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** All marks are conditional because a GC may happen while the
|
||||
** prototype is still being created
|
||||
*/
|
||||
static void traverseproto (global_State *g, Proto *f) {
|
||||
int i;
|
||||
if (f->source) stringmark(f->source);
|
||||
for (i=0; i<f->sizek; i++) /* mark literals */
|
||||
markvalue(g, &f->k[i]);
|
||||
for (i=0; i<f->sizeupvalues; i++) { /* mark upvalue names */
|
||||
if (f->upvalues[i])
|
||||
stringmark(f->upvalues[i]);
|
||||
}
|
||||
for (i=0; i<f->sizep; i++) { /* mark nested protos */
|
||||
if (f->p[i])
|
||||
markobject(g, f->p[i]);
|
||||
}
|
||||
for (i=0; i<f->sizelocvars; i++) { /* mark local-variable names */
|
||||
if (f->locvars[i].varname)
|
||||
stringmark(f->locvars[i].varname);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void traverseclosure (global_State *g, Closure *cl) {
|
||||
markobject(g, cl->c.env);
|
||||
if (cl->c.isC) {
|
||||
int i;
|
||||
for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */
|
||||
markvalue(g, &cl->c.upvalue[i]);
|
||||
}
|
||||
else {
|
||||
int i;
|
||||
lua_assert(cl->l.nupvalues == cl->l.p->nups);
|
||||
markobject(g, cl->l.p);
|
||||
for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */
|
||||
markobject(g, cl->l.upvals[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void checkstacksizes (lua_State *L, StkId max) {
|
||||
int ci_used = cast_int(L->ci - L->base_ci); /* number of `ci' in use */
|
||||
int s_used = cast_int(max - L->stack); /* part of stack in use */
|
||||
if (L->size_ci > LUAI_MAXCALLS) /* handling overflow? */
|
||||
return; /* do not touch the stacks */
|
||||
if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci)
|
||||
luaD_reallocCI(L, L->size_ci/2); /* still big enough... */
|
||||
condhardstacktests(luaD_reallocCI(L, ci_used + 1));
|
||||
if (4*s_used < L->stacksize &&
|
||||
2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize)
|
||||
luaD_reallocstack(L, L->stacksize/2); /* still big enough... */
|
||||
condhardstacktests(luaD_reallocstack(L, s_used));
|
||||
}
|
||||
|
||||
|
||||
static void traversestack (global_State *g, lua_State *l) {
|
||||
StkId o, lim;
|
||||
CallInfo *ci;
|
||||
markvalue(g, gt(l));
|
||||
lim = l->top;
|
||||
for (ci = l->base_ci; ci <= l->ci; ci++) {
|
||||
lua_assert(ci->top <= l->stack_last);
|
||||
if (lim < ci->top) lim = ci->top;
|
||||
}
|
||||
for (o = l->stack; o < l->top; o++)
|
||||
markvalue(g, o);
|
||||
for (; o <= lim; o++)
|
||||
setnilvalue(o);
|
||||
checkstacksizes(l, lim);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** traverse one gray object, turning it to black.
|
||||
** Returns `quantity' traversed.
|
||||
*/
|
||||
static l_mem propagatemark (global_State *g) {
|
||||
GCObject *o = g->gray;
|
||||
lua_assert(isgray(o));
|
||||
gray2black(o);
|
||||
switch (o->gch.tt) {
|
||||
case LUA_TTABLE: {
|
||||
Table *h = gco2h(o);
|
||||
g->gray = h->gclist;
|
||||
if (traversetable(g, h)) /* table is weak? */
|
||||
black2gray(o); /* keep it gray */
|
||||
return sizeof(Table) + sizeof(TValue) * h->sizearray +
|
||||
sizeof(Node) * sizenode(h);
|
||||
}
|
||||
case LUA_TFUNCTION: {
|
||||
Closure *cl = gco2cl(o);
|
||||
g->gray = cl->c.gclist;
|
||||
traverseclosure(g, cl);
|
||||
return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) :
|
||||
sizeLclosure(cl->l.nupvalues);
|
||||
}
|
||||
case LUA_TTHREAD: {
|
||||
lua_State *th = gco2th(o);
|
||||
g->gray = th->gclist;
|
||||
th->gclist = g->grayagain;
|
||||
g->grayagain = o;
|
||||
black2gray(o);
|
||||
traversestack(g, th);
|
||||
return sizeof(lua_State) + sizeof(TValue) * th->stacksize +
|
||||
sizeof(CallInfo) * th->size_ci;
|
||||
}
|
||||
case LUA_TPROTO: {
|
||||
Proto *p = gco2p(o);
|
||||
g->gray = p->gclist;
|
||||
traverseproto(g, p);
|
||||
return sizeof(Proto) + sizeof(Instruction) * p->sizecode +
|
||||
sizeof(Proto *) * p->sizep +
|
||||
sizeof(TValue) * p->sizek +
|
||||
sizeof(int) * p->sizelineinfo +
|
||||
sizeof(LocVar) * p->sizelocvars +
|
||||
sizeof(TString *) * p->sizeupvalues;
|
||||
}
|
||||
default: lua_assert(0); return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void propagateall (global_State *g) {
|
||||
while (g->gray) propagatemark(g);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** The next function tells whether a key or value can be cleared from
|
||||
** a weak table. Non-collectable objects are never removed from weak
|
||||
** tables. Strings behave as `values', so are never removed too. for
|
||||
** other objects: if really collected, cannot keep them; for userdata
|
||||
** being finalized, keep them in keys, but not in values
|
||||
*/
|
||||
static int iscleared (const TValue *o, int iskey) {
|
||||
if (!iscollectable(o)) return 0;
|
||||
if (ttisstring(o)) {
|
||||
stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */
|
||||
return 0;
|
||||
}
|
||||
return iswhite(gcvalue(o)) ||
|
||||
(ttisuserdata(o) && (!iskey && isfinalized(uvalue(o))));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** clear collected entries from weaktables
|
||||
*/
|
||||
static void cleartable (GCObject *l) {
|
||||
while (l) {
|
||||
Table *h = gco2h(l);
|
||||
int i = h->sizearray;
|
||||
lua_assert(testbit(h->marked, VALUEWEAKBIT) ||
|
||||
testbit(h->marked, KEYWEAKBIT));
|
||||
if (testbit(h->marked, VALUEWEAKBIT)) {
|
||||
while (i--) {
|
||||
TValue *o = &h->array[i];
|
||||
if (iscleared(o, 0)) /* value was collected? */
|
||||
setnilvalue(o); /* remove value */
|
||||
}
|
||||
}
|
||||
i = sizenode(h);
|
||||
while (i--) {
|
||||
Node *n = gnode(h, i);
|
||||
if (!ttisnil(gval(n)) && /* non-empty entry? */
|
||||
(iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) {
|
||||
setnilvalue(gval(n)); /* remove value ... */
|
||||
removeentry(n); /* remove entry from table */
|
||||
}
|
||||
}
|
||||
l = h->gclist;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void freeobj (lua_State *L, GCObject *o) {
|
||||
switch (o->gch.tt) {
|
||||
case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
|
||||
case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break;
|
||||
case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;
|
||||
case LUA_TTABLE: luaH_free(L, gco2h(o)); break;
|
||||
case LUA_TTHREAD: {
|
||||
lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread);
|
||||
luaE_freethread(L, gco2th(o));
|
||||
break;
|
||||
}
|
||||
case LUA_TSTRING: {
|
||||
G(L)->strt.nuse--;
|
||||
luaM_freemem(L, o, sizestring(gco2ts(o)));
|
||||
break;
|
||||
}
|
||||
case LUA_TUSERDATA: {
|
||||
luaM_freemem(L, o, sizeudata(gco2u(o)));
|
||||
break;
|
||||
}
|
||||
default: lua_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM)
|
||||
|
||||
|
||||
static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
|
||||
GCObject *curr;
|
||||
global_State *g = G(L);
|
||||
int deadmask = otherwhite(g);
|
||||
while ((curr = *p) != NULL && count-- > 0) {
|
||||
if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */
|
||||
sweepwholelist(L, &gco2th(curr)->openupval);
|
||||
if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */
|
||||
lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT));
|
||||
makewhite(g, curr); /* make it white (for next cycle) */
|
||||
p = &curr->gch.next;
|
||||
}
|
||||
else { /* must erase `curr' */
|
||||
lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
|
||||
*p = curr->gch.next;
|
||||
if (curr == g->rootgc) /* is the first element of the list? */
|
||||
g->rootgc = curr->gch.next; /* adjust first */
|
||||
freeobj(L, curr);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static void checkSizes (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
/* check size of string hash */
|
||||
if (g->strt.nuse < cast(lu_int32, g->strt.size/4) &&
|
||||
g->strt.size > MINSTRTABSIZE*2)
|
||||
luaS_resize(L, g->strt.size/2); /* table is too big */
|
||||
/* check size of buffer */
|
||||
if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */
|
||||
size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
|
||||
luaZ_resizebuffer(L, &g->buff, newsize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void GCTM (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
GCObject *o = g->tmudata->gch.next; /* get first element */
|
||||
Udata *udata = rawgco2u(o);
|
||||
const TValue *tm;
|
||||
/* remove udata from `tmudata' */
|
||||
if (o == g->tmudata) /* last element? */
|
||||
g->tmudata = NULL;
|
||||
else
|
||||
g->tmudata->gch.next = udata->uv.next;
|
||||
udata->uv.next = g->mainthread->next; /* return it to `root' list */
|
||||
g->mainthread->next = o;
|
||||
makewhite(g, o);
|
||||
tm = fasttm(L, udata->uv.metatable, TM_GC);
|
||||
if (tm != NULL) {
|
||||
lu_byte oldah = L->allowhook;
|
||||
lu_mem oldt = g->GCthreshold;
|
||||
L->allowhook = 0; /* stop debug hooks during GC tag method */
|
||||
g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */
|
||||
setobj2s(L, L->top, tm);
|
||||
setuvalue(L, L->top+1, udata);
|
||||
L->top += 2;
|
||||
luaD_call(L, L->top - 2, 0);
|
||||
L->allowhook = oldah; /* restore hooks */
|
||||
g->GCthreshold = oldt; /* restore threshold */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Call all GC tag methods
|
||||
*/
|
||||
void luaC_callGCTM (lua_State *L) {
|
||||
while (G(L)->tmudata)
|
||||
GCTM(L);
|
||||
}
|
||||
|
||||
|
||||
void luaC_freeall (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
int i;
|
||||
g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); /* mask to collect all elements */
|
||||
sweepwholelist(L, &g->rootgc);
|
||||
for (i = 0; i < g->strt.size; i++) /* free all string lists */
|
||||
sweepwholelist(L, &g->strt.hash[i]);
|
||||
}
|
||||
|
||||
|
||||
static void markmt (global_State *g) {
|
||||
int i;
|
||||
for (i=0; i<NUM_TAGS; i++)
|
||||
if (g->mt[i]) markobject(g, g->mt[i]);
|
||||
}
|
||||
|
||||
|
||||
/* mark root set */
|
||||
static void markroot (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
g->gray = NULL;
|
||||
g->grayagain = NULL;
|
||||
g->weak = NULL;
|
||||
markobject(g, g->mainthread);
|
||||
/* make global table be traversed before main stack */
|
||||
markvalue(g, gt(g->mainthread));
|
||||
markvalue(g, registry(L));
|
||||
markmt(g);
|
||||
g->gcstate = GCSpropagate;
|
||||
}
|
||||
|
||||
|
||||
static void remarkupvals (global_State *g) {
|
||||
UpVal *uv;
|
||||
for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
|
||||
lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
|
||||
if (isgray(obj2gco(uv)))
|
||||
markvalue(g, uv->v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void atomic (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
size_t udsize; /* total size of userdata to be finalized */
|
||||
/* remark occasional upvalues of (maybe) dead threads */
|
||||
remarkupvals(g);
|
||||
/* traverse objects cautch by write barrier and by 'remarkupvals' */
|
||||
propagateall(g);
|
||||
/* remark weak tables */
|
||||
g->gray = g->weak;
|
||||
g->weak = NULL;
|
||||
lua_assert(!iswhite(obj2gco(g->mainthread)));
|
||||
markobject(g, L); /* mark running thread */
|
||||
markmt(g); /* mark basic metatables (again) */
|
||||
propagateall(g);
|
||||
/* remark gray again */
|
||||
g->gray = g->grayagain;
|
||||
g->grayagain = NULL;
|
||||
propagateall(g);
|
||||
udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */
|
||||
marktmu(g); /* mark `preserved' userdata */
|
||||
propagateall(g); /* remark, to propagate `preserveness' */
|
||||
cleartable(g->weak); /* remove collected objects from weak tables */
|
||||
/* flip current white */
|
||||
g->currentwhite = cast_byte(otherwhite(g));
|
||||
g->sweepstrgc = 0;
|
||||
g->sweepgc = &g->rootgc;
|
||||
g->gcstate = GCSsweepstring;
|
||||
g->estimate = g->totalbytes - udsize; /* first estimate */
|
||||
}
|
||||
|
||||
|
||||
static l_mem singlestep (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
/*lua_checkmemory(L);*/
|
||||
switch (g->gcstate) {
|
||||
case GCSpause: {
|
||||
markroot(L); /* start a new collection */
|
||||
return 0;
|
||||
}
|
||||
case GCSpropagate: {
|
||||
if (g->gray)
|
||||
return propagatemark(g);
|
||||
else { /* no more `gray' objects */
|
||||
atomic(L); /* finish mark phase */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
case GCSsweepstring: {
|
||||
lu_mem old = g->totalbytes;
|
||||
sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
|
||||
if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */
|
||||
g->gcstate = GCSsweep; /* end sweep-string phase */
|
||||
lua_assert(old >= g->totalbytes);
|
||||
g->estimate -= old - g->totalbytes;
|
||||
return GCSWEEPCOST;
|
||||
}
|
||||
case GCSsweep: {
|
||||
lu_mem old = g->totalbytes;
|
||||
g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
|
||||
if (*g->sweepgc == NULL) { /* nothing more to sweep? */
|
||||
checkSizes(L);
|
||||
g->gcstate = GCSfinalize; /* end sweep phase */
|
||||
}
|
||||
lua_assert(old >= g->totalbytes);
|
||||
g->estimate -= old - g->totalbytes;
|
||||
return GCSWEEPMAX*GCSWEEPCOST;
|
||||
}
|
||||
case GCSfinalize: {
|
||||
if (g->tmudata) {
|
||||
GCTM(L);
|
||||
return GCFINALIZECOST;
|
||||
}
|
||||
else {
|
||||
g->gcstate = GCSpause; /* end collection */
|
||||
g->gcdept = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
default: lua_assert(0); return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaC_step (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul;
|
||||
if (lim == 0)
|
||||
lim = (MAX_LUMEM-1)/2; /* no limit */
|
||||
g->gcdept += g->totalbytes - g->GCthreshold;
|
||||
do {
|
||||
lim -= singlestep(L);
|
||||
if (g->gcstate == GCSpause)
|
||||
break;
|
||||
} while (lim > 0);
|
||||
if (g->gcstate != GCSpause) {
|
||||
if (g->gcdept < GCSTEPSIZE)
|
||||
g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/g->gcstepmul;*/
|
||||
else {
|
||||
g->gcdept -= GCSTEPSIZE;
|
||||
g->GCthreshold = g->totalbytes;
|
||||
}
|
||||
}
|
||||
else {
|
||||
lua_assert(g->totalbytes >= g->estimate);
|
||||
setthreshold(g);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaC_fullgc (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
if (g->gcstate <= GCSpropagate) {
|
||||
/* reset sweep marks to sweep all elements (returning them to white) */
|
||||
g->sweepstrgc = 0;
|
||||
g->sweepgc = &g->rootgc;
|
||||
/* reset other collector lists */
|
||||
g->gray = NULL;
|
||||
g->grayagain = NULL;
|
||||
g->weak = NULL;
|
||||
g->gcstate = GCSsweepstring;
|
||||
}
|
||||
lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate);
|
||||
/* finish any pending sweep phase */
|
||||
while (g->gcstate != GCSfinalize) {
|
||||
lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);
|
||||
singlestep(L);
|
||||
}
|
||||
markroot(L);
|
||||
while (g->gcstate != GCSpause) {
|
||||
singlestep(L);
|
||||
}
|
||||
setthreshold(g);
|
||||
}
|
||||
|
||||
|
||||
void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
|
||||
global_State *g = G(L);
|
||||
lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
|
||||
lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
|
||||
lua_assert(ttype(&o->gch) != LUA_TTABLE);
|
||||
/* must keep invariant? */
|
||||
if (g->gcstate == GCSpropagate)
|
||||
reallymarkobject(g, v); /* restore invariant */
|
||||
else /* don't mind */
|
||||
makewhite(g, o); /* mark as white just to avoid other barriers */
|
||||
}
|
||||
|
||||
|
||||
void luaC_barrierback (lua_State *L, Table *t) {
|
||||
global_State *g = G(L);
|
||||
GCObject *o = obj2gco(t);
|
||||
lua_assert(isblack(o) && !isdead(g, o));
|
||||
lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
|
||||
black2gray(o); /* make table gray (again) */
|
||||
t->gclist = g->grayagain;
|
||||
g->grayagain = o;
|
||||
}
|
||||
|
||||
|
||||
void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
|
||||
global_State *g = G(L);
|
||||
o->gch.next = g->rootgc;
|
||||
g->rootgc = o;
|
||||
o->gch.marked = luaC_white(g);
|
||||
o->gch.tt = tt;
|
||||
}
|
||||
|
||||
|
||||
void luaC_linkupval (lua_State *L, UpVal *uv) {
|
||||
global_State *g = G(L);
|
||||
GCObject *o = obj2gco(uv);
|
||||
o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */
|
||||
g->rootgc = o;
|
||||
if (isgray(o)) {
|
||||
if (g->gcstate == GCSpropagate) {
|
||||
gray2black(o); /* closed upvalues need barrier */
|
||||
luaC_barrier(L, uv, uv->v);
|
||||
}
|
||||
else { /* sweep phase: sweep it (turning it into white) */
|
||||
makewhite(g, o);
|
||||
lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
110
src/lua/lgc.h
Normal file
110
src/lua/lgc.h
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
** $Id: lgc.h,v 2.15 2005/08/24 16:15:49 roberto Exp $
|
||||
** Garbage Collector
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef lgc_h
|
||||
#define lgc_h
|
||||
|
||||
|
||||
#include "lobject.h"
|
||||
|
||||
|
||||
/*
|
||||
** Possible states of the Garbage Collector
|
||||
*/
|
||||
#define GCSpause 0
|
||||
#define GCSpropagate 1
|
||||
#define GCSsweepstring 2
|
||||
#define GCSsweep 3
|
||||
#define GCSfinalize 4
|
||||
|
||||
|
||||
/*
|
||||
** some userful bit tricks
|
||||
*/
|
||||
#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m)))
|
||||
#define setbits(x,m) ((x) |= (m))
|
||||
#define testbits(x,m) ((x) & (m))
|
||||
#define bitmask(b) (1<<(b))
|
||||
#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2))
|
||||
#define l_setbit(x,b) setbits(x, bitmask(b))
|
||||
#define resetbit(x,b) resetbits(x, bitmask(b))
|
||||
#define testbit(x,b) testbits(x, bitmask(b))
|
||||
#define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2)))
|
||||
#define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2)))
|
||||
#define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2)))
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Layout for bit use in `marked' field:
|
||||
** bit 0 - object is white (type 0)
|
||||
** bit 1 - object is white (type 1)
|
||||
** bit 2 - object is black
|
||||
** bit 3 - for userdata: has been finalized
|
||||
** bit 3 - for tables: has weak keys
|
||||
** bit 4 - for tables: has weak values
|
||||
** bit 5 - object is fixed (should not be collected)
|
||||
** bit 6 - object is "super" fixed (only the main thread)
|
||||
*/
|
||||
|
||||
|
||||
#define WHITE0BIT 0
|
||||
#define WHITE1BIT 1
|
||||
#define BLACKBIT 2
|
||||
#define FINALIZEDBIT 3
|
||||
#define KEYWEAKBIT 3
|
||||
#define VALUEWEAKBIT 4
|
||||
#define FIXEDBIT 5
|
||||
#define SFIXEDBIT 6
|
||||
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
|
||||
|
||||
|
||||
#define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT)
|
||||
#define isblack(x) testbit((x)->gch.marked, BLACKBIT)
|
||||
#define isgray(x) (!isblack(x) && !iswhite(x))
|
||||
|
||||
#define otherwhite(g) (g->currentwhite ^ WHITEBITS)
|
||||
#define isdead(g,v) ((v)->gch.marked & otherwhite(g) & WHITEBITS)
|
||||
|
||||
#define changewhite(x) ((x)->gch.marked ^= WHITEBITS)
|
||||
#define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT)
|
||||
|
||||
#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x)))
|
||||
|
||||
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
|
||||
|
||||
|
||||
#define luaC_checkGC(L) { \
|
||||
condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \
|
||||
if (G(L)->totalbytes >= G(L)->GCthreshold) \
|
||||
luaC_step(L); }
|
||||
|
||||
|
||||
#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \
|
||||
luaC_barrierf(L,obj2gco(p),gcvalue(v)); }
|
||||
|
||||
#define luaC_barriert(L,t,v) { if (valiswhite(v) && isblack(obj2gco(t))) \
|
||||
luaC_barrierback(L,t); }
|
||||
|
||||
#define luaC_objbarrier(L,p,o) \
|
||||
{ if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \
|
||||
luaC_barrierf(L,obj2gco(p),obj2gco(o)); }
|
||||
|
||||
#define luaC_objbarriert(L,t,o) \
|
||||
{ if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); }
|
||||
|
||||
LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all);
|
||||
LUAI_FUNC void luaC_callGCTM (lua_State *L);
|
||||
LUAI_FUNC void luaC_freeall (lua_State *L);
|
||||
LUAI_FUNC void luaC_step (lua_State *L);
|
||||
LUAI_FUNC void luaC_fullgc (lua_State *L);
|
||||
LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt);
|
||||
LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv);
|
||||
LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v);
|
||||
LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t);
|
||||
|
||||
|
||||
#endif
|
38
src/lua/linit.c
Normal file
38
src/lua/linit.c
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
** $Id: linit.c,v 1.14 2005/12/29 15:32:11 roberto Exp $
|
||||
** Initialization of libraries for lua.c
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#define linit_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
|
||||
static const luaL_Reg lualibs[] = {
|
||||
{"", luaopen_base},
|
||||
{LUA_LOADLIBNAME, luaopen_package},
|
||||
{LUA_TABLIBNAME, luaopen_table},
|
||||
{LUA_IOLIBNAME, luaopen_io},
|
||||
{LUA_OSLIBNAME, luaopen_os},
|
||||
{LUA_STRLIBNAME, luaopen_string},
|
||||
{LUA_MATHLIBNAME, luaopen_math},
|
||||
{LUA_DBLIBNAME, luaopen_debug},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
LUALIB_API void luaL_openlibs (lua_State *L) {
|
||||
const luaL_Reg *lib = lualibs;
|
||||
for (; lib->func; lib++) {
|
||||
lua_pushcfunction(L, lib->func);
|
||||
lua_pushstring(L, lib->name);
|
||||
lua_call(L, 1, 0);
|
||||
}
|
||||
}
|
||||
|
532
src/lua/liolib.c
Normal file
532
src/lua/liolib.c
Normal file
@ -0,0 +1,532 @@
|
||||
/*
|
||||
** $Id: liolib.c,v 2.72 2006/01/28 12:59:13 roberto Exp $
|
||||
** Standard I/O (and system) library
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define liolib_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
|
||||
|
||||
#define IO_INPUT 1
|
||||
#define IO_OUTPUT 2
|
||||
|
||||
|
||||
static const char *const fnames[] = {"input", "output"};
|
||||
|
||||
|
||||
static int pushresult (lua_State *L, int i, const char *filename) {
|
||||
int en = errno; /* calls to Lua API may change this value */
|
||||
if (i) {
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
if (filename)
|
||||
lua_pushfstring(L, "%s: %s", filename, strerror(en));
|
||||
else
|
||||
lua_pushfstring(L, "%s", strerror(en));
|
||||
lua_pushinteger(L, en);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void fileerror (lua_State *L, int arg, const char *filename) {
|
||||
lua_pushfstring(L, "%s: %s", filename, strerror(errno));
|
||||
luaL_argerror(L, arg, lua_tostring(L, -1));
|
||||
}
|
||||
|
||||
|
||||
#define topfile(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE))
|
||||
|
||||
|
||||
static int io_type (lua_State *L) {
|
||||
void *ud;
|
||||
luaL_checkany(L, 1);
|
||||
ud = lua_touserdata(L, 1);
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
|
||||
if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1))
|
||||
lua_pushnil(L); /* not a file */
|
||||
else if (*((FILE **)ud) == NULL)
|
||||
lua_pushliteral(L, "closed file");
|
||||
else
|
||||
lua_pushliteral(L, "file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static FILE *tofile (lua_State *L) {
|
||||
FILE **f = topfile(L);
|
||||
if (*f == NULL)
|
||||
luaL_error(L, "attempt to use a closed file");
|
||||
return *f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** When creating file handles, always creates a `closed' file handle
|
||||
** before opening the actual file; so, if there is a memory error, the
|
||||
** file is not left opened.
|
||||
*/
|
||||
static FILE **newfile (lua_State *L) {
|
||||
FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *));
|
||||
*pf = NULL; /* file handle is currently `closed' */
|
||||
luaL_getmetatable(L, LUA_FILEHANDLE);
|
||||
lua_setmetatable(L, -2);
|
||||
return pf;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** this function has a separated environment, which defines the
|
||||
** correct __close for 'popen' files
|
||||
*/
|
||||
static int io_pclose (lua_State *L) {
|
||||
FILE **p = topfile(L);
|
||||
int ok = lua_pclose(L, *p);
|
||||
if (ok) *p = NULL;
|
||||
return pushresult(L, ok, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int io_fclose (lua_State *L) {
|
||||
FILE **p = topfile(L);
|
||||
int ok = (fclose(*p) == 0);
|
||||
if (ok) *p = NULL;
|
||||
return pushresult(L, ok, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int aux_close (lua_State *L) {
|
||||
lua_getfenv(L, 1);
|
||||
lua_getfield(L, -1, "__close");
|
||||
return (lua_tocfunction(L, -1))(L);
|
||||
}
|
||||
|
||||
|
||||
static int io_close (lua_State *L) {
|
||||
if (lua_isnone(L, 1))
|
||||
lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT);
|
||||
tofile(L); /* make sure argument is a file */
|
||||
return aux_close(L);
|
||||
}
|
||||
|
||||
|
||||
static int io_gc (lua_State *L) {
|
||||
FILE *f = *topfile(L);
|
||||
/* ignore closed files and standard files */
|
||||
if (f != NULL && f != stdin && f != stdout && f != stderr)
|
||||
aux_close(L);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int io_tostring (lua_State *L) {
|
||||
FILE *f = *topfile(L);
|
||||
if (f == NULL)
|
||||
lua_pushstring(L, "file (closed)");
|
||||
else
|
||||
lua_pushfstring(L, "file (%p)", f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int io_open (lua_State *L) {
|
||||
const char *filename = luaL_checkstring(L, 1);
|
||||
const char *mode = luaL_optstring(L, 2, "r");
|
||||
FILE **pf = newfile(L);
|
||||
*pf = fopen(filename, mode);
|
||||
return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
|
||||
}
|
||||
|
||||
|
||||
static int io_popen (lua_State *L) {
|
||||
const char *filename = luaL_checkstring(L, 1);
|
||||
const char *mode = luaL_optstring(L, 2, "r");
|
||||
FILE **pf = newfile(L);
|
||||
*pf = lua_popen(L, filename, mode);
|
||||
return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
|
||||
}
|
||||
|
||||
|
||||
static int io_tmpfile (lua_State *L) {
|
||||
FILE **pf = newfile(L);
|
||||
*pf = tmpfile();
|
||||
return (*pf == NULL) ? pushresult(L, 0, NULL) : 1;
|
||||
}
|
||||
|
||||
|
||||
static FILE *getiofile (lua_State *L, int findex) {
|
||||
FILE *f;
|
||||
lua_rawgeti(L, LUA_ENVIRONINDEX, findex);
|
||||
f = *(FILE **)lua_touserdata(L, -1);
|
||||
if (f == NULL)
|
||||
luaL_error(L, "standard %s file is closed", fnames[findex - 1]);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
static int g_iofile (lua_State *L, int f, const char *mode) {
|
||||
if (!lua_isnoneornil(L, 1)) {
|
||||
const char *filename = lua_tostring(L, 1);
|
||||
if (filename) {
|
||||
FILE **pf = newfile(L);
|
||||
*pf = fopen(filename, mode);
|
||||
if (*pf == NULL)
|
||||
fileerror(L, 1, filename);
|
||||
}
|
||||
else {
|
||||
tofile(L); /* check that it's a valid file handle */
|
||||
lua_pushvalue(L, 1);
|
||||
}
|
||||
lua_rawseti(L, LUA_ENVIRONINDEX, f);
|
||||
}
|
||||
/* return current value */
|
||||
lua_rawgeti(L, LUA_ENVIRONINDEX, f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int io_input (lua_State *L) {
|
||||
return g_iofile(L, IO_INPUT, "r");
|
||||
}
|
||||
|
||||
|
||||
static int io_output (lua_State *L) {
|
||||
return g_iofile(L, IO_OUTPUT, "w");
|
||||
}
|
||||
|
||||
|
||||
static int io_readline (lua_State *L);
|
||||
|
||||
|
||||
static void aux_lines (lua_State *L, int idx, int toclose) {
|
||||
lua_pushvalue(L, idx);
|
||||
lua_pushboolean(L, toclose); /* close/not close file when finished */
|
||||
lua_pushcclosure(L, io_readline, 2);
|
||||
}
|
||||
|
||||
|
||||
static int f_lines (lua_State *L) {
|
||||
tofile(L); /* check that it's a valid file handle */
|
||||
aux_lines(L, 1, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int io_lines (lua_State *L) {
|
||||
if (lua_isnoneornil(L, 1)) { /* no arguments? */
|
||||
/* will iterate over default input */
|
||||
lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT);
|
||||
return f_lines(L);
|
||||
}
|
||||
else {
|
||||
const char *filename = luaL_checkstring(L, 1);
|
||||
FILE **pf = newfile(L);
|
||||
*pf = fopen(filename, "r");
|
||||
if (*pf == NULL)
|
||||
fileerror(L, 1, filename);
|
||||
aux_lines(L, lua_gettop(L), 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** READ
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
|
||||
static int read_number (lua_State *L, FILE *f) {
|
||||
lua_Number d;
|
||||
if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) {
|
||||
lua_pushnumber(L, d);
|
||||
return 1;
|
||||
}
|
||||
else return 0; /* read fails */
|
||||
}
|
||||
|
||||
|
||||
static int test_eof (lua_State *L, FILE *f) {
|
||||
int c = getc(f);
|
||||
ungetc(c, f);
|
||||
lua_pushlstring(L, NULL, 0);
|
||||
return (c != EOF);
|
||||
}
|
||||
|
||||
|
||||
static int read_line (lua_State *L, FILE *f) {
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L, &b);
|
||||
for (;;) {
|
||||
size_t l;
|
||||
char *p = luaL_prepbuffer(&b);
|
||||
if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */
|
||||
luaL_pushresult(&b); /* close buffer */
|
||||
return (lua_strlen(L, -1) > 0); /* check whether read something */
|
||||
}
|
||||
l = strlen(p);
|
||||
if (l == 0 || p[l-1] != '\n')
|
||||
luaL_addsize(&b, l);
|
||||
else {
|
||||
luaL_addsize(&b, l - 1); /* do not include `eol' */
|
||||
luaL_pushresult(&b); /* close buffer */
|
||||
return 1; /* read at least an `eol' */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int read_chars (lua_State *L, FILE *f, size_t n) {
|
||||
size_t rlen; /* how much to read */
|
||||
size_t nr; /* number of chars actually read */
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L, &b);
|
||||
rlen = LUAL_BUFFERSIZE; /* try to read that much each time */
|
||||
do {
|
||||
char *p = luaL_prepbuffer(&b);
|
||||
if (rlen > n) rlen = n; /* cannot read more than asked */
|
||||
nr = fread(p, sizeof(char), rlen, f);
|
||||
luaL_addsize(&b, nr);
|
||||
n -= nr; /* still have to read `n' chars */
|
||||
} while (n > 0 && nr == rlen); /* until end of count or eof */
|
||||
luaL_pushresult(&b); /* close buffer */
|
||||
return (n == 0 || lua_strlen(L, -1) > 0);
|
||||
}
|
||||
|
||||
|
||||
static int g_read (lua_State *L, FILE *f, int first) {
|
||||
int nargs = lua_gettop(L) - 1;
|
||||
int success;
|
||||
int n;
|
||||
clearerr(f);
|
||||
if (nargs == 0) { /* no arguments? */
|
||||
success = read_line(L, f);
|
||||
n = first+1; /* to return 1 result */
|
||||
}
|
||||
else { /* ensure stack space for all results and for auxlib's buffer */
|
||||
luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
|
||||
success = 1;
|
||||
for (n = first; nargs-- && success; n++) {
|
||||
if (lua_type(L, n) == LUA_TNUMBER) {
|
||||
size_t l = (size_t)lua_tointeger(L, n);
|
||||
success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
|
||||
}
|
||||
else {
|
||||
const char *p = lua_tostring(L, n);
|
||||
luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
|
||||
switch (p[1]) {
|
||||
case 'n': /* number */
|
||||
success = read_number(L, f);
|
||||
break;
|
||||
case 'l': /* line */
|
||||
success = read_line(L, f);
|
||||
break;
|
||||
case 'a': /* file */
|
||||
read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */
|
||||
success = 1; /* always success */
|
||||
break;
|
||||
default:
|
||||
return luaL_argerror(L, n, "invalid format");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ferror(f))
|
||||
return pushresult(L, 0, NULL);
|
||||
if (!success) {
|
||||
lua_pop(L, 1); /* remove last result */
|
||||
lua_pushnil(L); /* push nil instead */
|
||||
}
|
||||
return n - first;
|
||||
}
|
||||
|
||||
|
||||
static int io_read (lua_State *L) {
|
||||
return g_read(L, getiofile(L, IO_INPUT), 1);
|
||||
}
|
||||
|
||||
|
||||
static int f_read (lua_State *L) {
|
||||
return g_read(L, tofile(L), 2);
|
||||
}
|
||||
|
||||
|
||||
static int io_readline (lua_State *L) {
|
||||
FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1));
|
||||
int sucess;
|
||||
if (f == NULL) /* file is already closed? */
|
||||
luaL_error(L, "file is already closed");
|
||||
sucess = read_line(L, f);
|
||||
if (ferror(f))
|
||||
return luaL_error(L, "%s", strerror(errno));
|
||||
if (sucess) return 1;
|
||||
else { /* EOF */
|
||||
if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */
|
||||
lua_settop(L, 0);
|
||||
lua_pushvalue(L, lua_upvalueindex(1));
|
||||
aux_close(L); /* close it */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
static int g_write (lua_State *L, FILE *f, int arg) {
|
||||
int nargs = lua_gettop(L) - 1;
|
||||
int status = 1;
|
||||
for (; nargs--; arg++) {
|
||||
if (lua_type(L, arg) == LUA_TNUMBER) {
|
||||
/* optimization: could be done exactly as for strings */
|
||||
status = status &&
|
||||
fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
|
||||
}
|
||||
else {
|
||||
size_t l;
|
||||
const char *s = luaL_checklstring(L, arg, &l);
|
||||
status = status && (fwrite(s, sizeof(char), l, f) == l);
|
||||
}
|
||||
}
|
||||
return pushresult(L, status, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int io_write (lua_State *L) {
|
||||
return g_write(L, getiofile(L, IO_OUTPUT), 1);
|
||||
}
|
||||
|
||||
|
||||
static int f_write (lua_State *L) {
|
||||
return g_write(L, tofile(L), 2);
|
||||
}
|
||||
|
||||
|
||||
static int f_seek (lua_State *L) {
|
||||
static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
|
||||
static const char *const modenames[] = {"set", "cur", "end", NULL};
|
||||
FILE *f = tofile(L);
|
||||
int op = luaL_checkoption(L, 2, "cur", modenames);
|
||||
long offset = luaL_optlong(L, 3, 0);
|
||||
op = fseek(f, offset, mode[op]);
|
||||
if (op)
|
||||
return pushresult(L, 0, NULL); /* error */
|
||||
else {
|
||||
lua_pushinteger(L, ftell(f));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int f_setvbuf (lua_State *L) {
|
||||
static const int mode[] = {_IONBF, _IOFBF, _IOLBF};
|
||||
static const char *const modenames[] = {"no", "full", "line", NULL};
|
||||
FILE *f = tofile(L);
|
||||
int op = luaL_checkoption(L, 2, NULL, modenames);
|
||||
lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
|
||||
int res = setvbuf(f, NULL, mode[op], sz);
|
||||
return pushresult(L, res == 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int io_flush (lua_State *L) {
|
||||
return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int f_flush (lua_State *L) {
|
||||
return pushresult(L, fflush(tofile(L)) == 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
static const luaL_Reg iolib[] = {
|
||||
{"close", io_close},
|
||||
{"flush", io_flush},
|
||||
{"input", io_input},
|
||||
{"lines", io_lines},
|
||||
{"open", io_open},
|
||||
{"output", io_output},
|
||||
{"popen", io_popen},
|
||||
{"read", io_read},
|
||||
{"tmpfile", io_tmpfile},
|
||||
{"type", io_type},
|
||||
{"write", io_write},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
static const luaL_Reg flib[] = {
|
||||
{"close", io_close},
|
||||
{"flush", f_flush},
|
||||
{"lines", f_lines},
|
||||
{"read", f_read},
|
||||
{"seek", f_seek},
|
||||
{"setvbuf", f_setvbuf},
|
||||
{"write", f_write},
|
||||
{"__gc", io_gc},
|
||||
{"__tostring", io_tostring},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
static void createmeta (lua_State *L) {
|
||||
luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */
|
||||
lua_pushvalue(L, -1); /* push metatable */
|
||||
lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
|
||||
luaL_register(L, NULL, flib); /* file methods */
|
||||
}
|
||||
|
||||
|
||||
static void createstdfile (lua_State *L, FILE *f, int k, const char *fname) {
|
||||
*newfile(L) = f;
|
||||
if (k > 0) {
|
||||
lua_pushvalue(L, -1);
|
||||
lua_rawseti(L, LUA_ENVIRONINDEX, k);
|
||||
}
|
||||
lua_setfield(L, -2, fname);
|
||||
}
|
||||
|
||||
|
||||
LUALIB_API int luaopen_io (lua_State *L) {
|
||||
createmeta(L);
|
||||
/* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */
|
||||
lua_createtable(L, 2, 1);
|
||||
lua_replace(L, LUA_ENVIRONINDEX);
|
||||
/* open library */
|
||||
luaL_register(L, LUA_IOLIBNAME, iolib);
|
||||
/* create (and set) default files */
|
||||
createstdfile(L, stdin, IO_INPUT, "stdin");
|
||||
createstdfile(L, stdout, IO_OUTPUT, "stdout");
|
||||
createstdfile(L, stderr, 0, "stderr");
|
||||
/* create environment for 'popen' */
|
||||
lua_getfield(L, -1, "popen");
|
||||
lua_createtable(L, 0, 1);
|
||||
lua_pushcfunction(L, io_pclose);
|
||||
lua_setfield(L, -2, "__close");
|
||||
lua_setfenv(L, -2);
|
||||
lua_pop(L, 1); /* pop 'popen' */
|
||||
/* set default close function */
|
||||
lua_pushcfunction(L, io_fclose);
|
||||
lua_setfield(L, LUA_ENVIRONINDEX, "__close");
|
||||
return 1;
|
||||
}
|
||||
|
460
src/lua/llex.c
Normal file
460
src/lua/llex.c
Normal file
@ -0,0 +1,460 @@
|
||||
/*
|
||||
** $Id: llex.c,v 2.19 2006/02/06 18:28:16 roberto Exp $
|
||||
** Lexical Analyzer
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <locale.h>
|
||||
#include <string.h>
|
||||
|
||||
#define llex_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "ldo.h"
|
||||
#include "llex.h"
|
||||
#include "lobject.h"
|
||||
#include "lparser.h"
|
||||
#include "lstate.h"
|
||||
#include "lstring.h"
|
||||
#include "lzio.h"
|
||||
|
||||
|
||||
|
||||
#define next(ls) (ls->current = zgetc(ls->z))
|
||||
|
||||
|
||||
|
||||
|
||||
#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r')
|
||||
|
||||
|
||||
/* ORDER RESERVED */
|
||||
const char *const luaX_tokens [] = {
|
||||
"and", "break", "do", "else", "elseif",
|
||||
"end", "false", "for", "function", "if",
|
||||
"in", "local", "nil", "not", "or", "repeat",
|
||||
"return", "then", "true", "until", "while",
|
||||
"..", "...", "==", ">=", "<=", "~=",
|
||||
"<number>", "<name>", "<string>", "<eof>",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
#define save_and_next(ls) (save(ls, ls->current), next(ls))
|
||||
|
||||
|
||||
static void save (LexState *ls, int c) {
|
||||
Mbuffer *b = ls->buff;
|
||||
if (b->n + 1 > b->buffsize) {
|
||||
size_t newsize;
|
||||
if (b->buffsize >= MAX_SIZET/2)
|
||||
luaX_lexerror(ls, "lexical element too long", 0);
|
||||
newsize = b->buffsize * 2;
|
||||
luaZ_resizebuffer(ls->L, b, newsize);
|
||||
}
|
||||
b->buffer[b->n++] = cast(char, c);
|
||||
}
|
||||
|
||||
|
||||
void luaX_init (lua_State *L) {
|
||||
int i;
|
||||
for (i=0; i<NUM_RESERVED; i++) {
|
||||
TString *ts = luaS_new(L, luaX_tokens[i]);
|
||||
luaS_fix(ts); /* reserved words are never collected */
|
||||
lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN);
|
||||
ts->tsv.reserved = cast_byte(i+1); /* reserved word */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define MAXSRC 80
|
||||
|
||||
|
||||
const char *luaX_token2str (LexState *ls, int token) {
|
||||
if (token < FIRST_RESERVED) {
|
||||
lua_assert(token == cast(unsigned char, token));
|
||||
return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) :
|
||||
luaO_pushfstring(ls->L, "%c", token);
|
||||
}
|
||||
else
|
||||
return luaX_tokens[token-FIRST_RESERVED];
|
||||
}
|
||||
|
||||
|
||||
static const char *txtToken (LexState *ls, int token) {
|
||||
switch (token) {
|
||||
case TK_NAME:
|
||||
case TK_STRING:
|
||||
case TK_NUMBER:
|
||||
save(ls, '\0');
|
||||
return luaZ_buffer(ls->buff);
|
||||
default:
|
||||
return luaX_token2str(ls, token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaX_lexerror (LexState *ls, const char *msg, int token) {
|
||||
char buff[MAXSRC];
|
||||
luaO_chunkid(buff, getstr(ls->source), MAXSRC);
|
||||
msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg);
|
||||
if (token)
|
||||
luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token));
|
||||
luaD_throw(ls->L, LUA_ERRSYNTAX);
|
||||
}
|
||||
|
||||
|
||||
void luaX_syntaxerror (LexState *ls, const char *msg) {
|
||||
luaX_lexerror(ls, msg, ls->t.token);
|
||||
}
|
||||
|
||||
|
||||
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
|
||||
lua_State *L = ls->L;
|
||||
TString *ts = luaS_newlstr(L, str, l);
|
||||
TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */
|
||||
if (ttisnil(o))
|
||||
setbvalue(o, 1); /* make sure `str' will not be collected */
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
static void inclinenumber (LexState *ls) {
|
||||
int old = ls->current;
|
||||
lua_assert(currIsNewline(ls));
|
||||
next(ls); /* skip `\n' or `\r' */
|
||||
if (currIsNewline(ls) && ls->current != old)
|
||||
next(ls); /* skip `\n\r' or `\r\n' */
|
||||
if (++ls->linenumber >= MAX_INT)
|
||||
luaX_syntaxerror(ls, "chunk has too many lines");
|
||||
}
|
||||
|
||||
|
||||
void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) {
|
||||
ls->decpoint = '.';
|
||||
ls->L = L;
|
||||
ls->lookahead.token = TK_EOS; /* no look-ahead token */
|
||||
ls->z = z;
|
||||
ls->fs = NULL;
|
||||
ls->linenumber = 1;
|
||||
ls->lastline = 1;
|
||||
ls->source = source;
|
||||
luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
|
||||
next(ls); /* read first char */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** =======================================================
|
||||
** LEXICAL ANALYZER
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
|
||||
|
||||
static int check_next (LexState *ls, const char *set) {
|
||||
if (!strchr(set, ls->current))
|
||||
return 0;
|
||||
save_and_next(ls);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void buffreplace (LexState *ls, char from, char to) {
|
||||
size_t n = luaZ_bufflen(ls->buff);
|
||||
char *p = luaZ_buffer(ls->buff);
|
||||
while (n--)
|
||||
if (p[n] == from) p[n] = to;
|
||||
}
|
||||
|
||||
|
||||
static void trydecpoint (LexState *ls, SemInfo *seminfo) {
|
||||
/* format error: try to update decimal point separator */
|
||||
struct lconv *cv = localeconv();
|
||||
char old = ls->decpoint;
|
||||
ls->decpoint = (cv ? cv->decimal_point[0] : '.');
|
||||
buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */
|
||||
if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) {
|
||||
/* format error with correct decimal point: no more options */
|
||||
buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */
|
||||
luaX_lexerror(ls, "malformed number", TK_NUMBER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* LUA_NUMBER */
|
||||
static void read_numeral (LexState *ls, SemInfo *seminfo) {
|
||||
lua_assert(isdigit(ls->current));
|
||||
do {
|
||||
save_and_next(ls);
|
||||
} while (isdigit(ls->current) || ls->current == '.');
|
||||
if (check_next(ls, "Ee")) /* `E'? */
|
||||
check_next(ls, "+-"); /* optional exponent sign */
|
||||
while (isalnum(ls->current) || ls->current == '_')
|
||||
save_and_next(ls);
|
||||
save(ls, '\0');
|
||||
buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
|
||||
if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) /* format error? */
|
||||
trydecpoint(ls, seminfo); /* try to update decimal point separator */
|
||||
}
|
||||
|
||||
|
||||
static int skip_sep (LexState *ls) {
|
||||
int count = 0;
|
||||
int s = ls->current;
|
||||
lua_assert(s == '[' || s == ']');
|
||||
save_and_next(ls);
|
||||
while (ls->current == '=') {
|
||||
save_and_next(ls);
|
||||
count++;
|
||||
}
|
||||
return (ls->current == s) ? count : (-count) - 1;
|
||||
}
|
||||
|
||||
|
||||
static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
|
||||
int cont = 0;
|
||||
(void)(cont); /* avoid warnings when `cont' is not used */
|
||||
save_and_next(ls); /* skip 2nd `[' */
|
||||
if (currIsNewline(ls)) /* string starts with a newline? */
|
||||
inclinenumber(ls); /* skip it */
|
||||
for (;;) {
|
||||
switch (ls->current) {
|
||||
case EOZ:
|
||||
luaX_lexerror(ls, (seminfo) ? "unfinished long string" :
|
||||
"unfinished long comment", TK_EOS);
|
||||
break; /* to avoid warnings */
|
||||
#if defined(LUA_COMPAT_LSTR)
|
||||
case '[': {
|
||||
if (skip_sep(ls) == sep) {
|
||||
save_and_next(ls); /* skip 2nd `[' */
|
||||
cont++;
|
||||
#if LUA_COMPAT_LSTR == 1
|
||||
if (sep == 0)
|
||||
luaX_lexerror(ls, "nesting of [[...]] is deprecated", '[');
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case ']': {
|
||||
if (skip_sep(ls) == sep) {
|
||||
save_and_next(ls); /* skip 2nd `]' */
|
||||
#if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2
|
||||
cont--;
|
||||
if (sep == 0 && cont >= 0) break;
|
||||
#endif
|
||||
goto endloop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '\n':
|
||||
case '\r': {
|
||||
save(ls, '\n');
|
||||
inclinenumber(ls);
|
||||
if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (seminfo) save_and_next(ls);
|
||||
else next(ls);
|
||||
}
|
||||
}
|
||||
} endloop:
|
||||
if (seminfo)
|
||||
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep),
|
||||
luaZ_bufflen(ls->buff) - 2*(2 + sep));
|
||||
}
|
||||
|
||||
|
||||
static void read_string (LexState *ls, int del, SemInfo *seminfo) {
|
||||
save_and_next(ls);
|
||||
while (ls->current != del) {
|
||||
switch (ls->current) {
|
||||
case EOZ:
|
||||
luaX_lexerror(ls, "unfinished string", TK_EOS);
|
||||
continue; /* to avoid warnings */
|
||||
case '\n':
|
||||
case '\r':
|
||||
luaX_lexerror(ls, "unfinished string", TK_STRING);
|
||||
continue; /* to avoid warnings */
|
||||
case '\\': {
|
||||
int c;
|
||||
next(ls); /* do not save the `\' */
|
||||
switch (ls->current) {
|
||||
case 'a': c = '\a'; break;
|
||||
case 'b': c = '\b'; break;
|
||||
case 'f': c = '\f'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
case 't': c = '\t'; break;
|
||||
case 'v': c = '\v'; break;
|
||||
case '\n': /* go through */
|
||||
case '\r': save(ls, '\n'); inclinenumber(ls); continue;
|
||||
case EOZ: continue; /* will raise an error next loop */
|
||||
default: {
|
||||
if (!isdigit(ls->current))
|
||||
save_and_next(ls); /* handles \\, \", \', and \? */
|
||||
else { /* \xxx */
|
||||
int i = 0;
|
||||
c = 0;
|
||||
do {
|
||||
c = 10*c + (ls->current-'0');
|
||||
next(ls);
|
||||
} while (++i<3 && isdigit(ls->current));
|
||||
if (c > UCHAR_MAX)
|
||||
luaX_lexerror(ls, "escape sequence too large", TK_STRING);
|
||||
save(ls, c);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
save(ls, c);
|
||||
next(ls);
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
save_and_next(ls);
|
||||
}
|
||||
}
|
||||
save_and_next(ls); /* skip delimiter */
|
||||
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1,
|
||||
luaZ_bufflen(ls->buff) - 2);
|
||||
}
|
||||
|
||||
|
||||
static int llex (LexState *ls, SemInfo *seminfo) {
|
||||
luaZ_resetbuffer(ls->buff);
|
||||
for (;;) {
|
||||
switch (ls->current) {
|
||||
case '\n':
|
||||
case '\r': {
|
||||
inclinenumber(ls);
|
||||
continue;
|
||||
}
|
||||
case '-': {
|
||||
next(ls);
|
||||
if (ls->current != '-') return '-';
|
||||
/* else is a comment */
|
||||
next(ls);
|
||||
if (ls->current == '[') {
|
||||
int sep = skip_sep(ls);
|
||||
luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */
|
||||
if (sep >= 0) {
|
||||
read_long_string(ls, NULL, sep); /* long comment */
|
||||
luaZ_resetbuffer(ls->buff);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* else short comment */
|
||||
while (!currIsNewline(ls) && ls->current != EOZ)
|
||||
next(ls);
|
||||
continue;
|
||||
}
|
||||
case '[': {
|
||||
int sep = skip_sep(ls);
|
||||
if (sep >= 0) {
|
||||
read_long_string(ls, seminfo, sep);
|
||||
return TK_STRING;
|
||||
}
|
||||
else if (sep == -1) return '[';
|
||||
else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING);
|
||||
}
|
||||
case '=': {
|
||||
next(ls);
|
||||
if (ls->current != '=') return '=';
|
||||
else { next(ls); return TK_EQ; }
|
||||
}
|
||||
case '<': {
|
||||
next(ls);
|
||||
if (ls->current != '=') return '<';
|
||||
else { next(ls); return TK_LE; }
|
||||
}
|
||||
case '>': {
|
||||
next(ls);
|
||||
if (ls->current != '=') return '>';
|
||||
else { next(ls); return TK_GE; }
|
||||
}
|
||||
case '~': {
|
||||
next(ls);
|
||||
if (ls->current != '=') return '~';
|
||||
else { next(ls); return TK_NE; }
|
||||
}
|
||||
case '"':
|
||||
case '\'': {
|
||||
read_string(ls, ls->current, seminfo);
|
||||
return TK_STRING;
|
||||
}
|
||||
case '.': {
|
||||
save_and_next(ls);
|
||||
if (check_next(ls, ".")) {
|
||||
if (check_next(ls, "."))
|
||||
return TK_DOTS; /* ... */
|
||||
else return TK_CONCAT; /* .. */
|
||||
}
|
||||
else if (!isdigit(ls->current)) return '.';
|
||||
else {
|
||||
read_numeral(ls, seminfo);
|
||||
return TK_NUMBER;
|
||||
}
|
||||
}
|
||||
case EOZ: {
|
||||
return TK_EOS;
|
||||
}
|
||||
default: {
|
||||
if (isspace(ls->current)) {
|
||||
lua_assert(!currIsNewline(ls));
|
||||
next(ls);
|
||||
continue;
|
||||
}
|
||||
else if (isdigit(ls->current)) {
|
||||
read_numeral(ls, seminfo);
|
||||
return TK_NUMBER;
|
||||
}
|
||||
else if (isalpha(ls->current) || ls->current == '_') {
|
||||
/* identifier or reserved word */
|
||||
TString *ts;
|
||||
do {
|
||||
save_and_next(ls);
|
||||
} while (isalnum(ls->current) || ls->current == '_');
|
||||
ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
|
||||
luaZ_bufflen(ls->buff));
|
||||
if (ts->tsv.reserved > 0) /* reserved word? */
|
||||
return ts->tsv.reserved - 1 + FIRST_RESERVED;
|
||||
else {
|
||||
seminfo->ts = ts;
|
||||
return TK_NAME;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int c = ls->current;
|
||||
next(ls);
|
||||
return c; /* single-char tokens (+ - / ...) */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaX_next (LexState *ls) {
|
||||
ls->lastline = ls->linenumber;
|
||||
if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */
|
||||
ls->t = ls->lookahead; /* use this one */
|
||||
ls->lookahead.token = TK_EOS; /* and discharge it */
|
||||
}
|
||||
else
|
||||
ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */
|
||||
}
|
||||
|
||||
|
||||
void luaX_lookahead (LexState *ls) {
|
||||
lua_assert(ls->lookahead.token == TK_EOS);
|
||||
ls->lookahead.token = llex(ls, &ls->lookahead.seminfo);
|
||||
}
|
||||
|
81
src/lua/llex.h
Normal file
81
src/lua/llex.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
** $Id: llex.h,v 1.57 2005/12/07 15:43:05 roberto Exp $
|
||||
** Lexical Analyzer
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef llex_h
|
||||
#define llex_h
|
||||
|
||||
#include "lobject.h"
|
||||
#include "lzio.h"
|
||||
|
||||
|
||||
#define FIRST_RESERVED 257
|
||||
|
||||
/* maximum length of a reserved word */
|
||||
#define TOKEN_LEN (sizeof("function")/sizeof(char))
|
||||
|
||||
|
||||
/*
|
||||
* WARNING: if you change the order of this enumeration,
|
||||
* grep "ORDER RESERVED"
|
||||
*/
|
||||
enum RESERVED {
|
||||
/* terminal symbols denoted by reserved words */
|
||||
TK_AND = FIRST_RESERVED, TK_BREAK,
|
||||
TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
|
||||
TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
|
||||
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
|
||||
/* other terminal symbols */
|
||||
TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER,
|
||||
TK_NAME, TK_STRING, TK_EOS
|
||||
};
|
||||
|
||||
/* number of reserved words */
|
||||
#define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1))
|
||||
|
||||
|
||||
/* array with token `names' */
|
||||
LUAI_DATA const char *const luaX_tokens [];
|
||||
|
||||
|
||||
typedef union {
|
||||
lua_Number r;
|
||||
TString *ts;
|
||||
} SemInfo; /* semantics information */
|
||||
|
||||
|
||||
typedef struct Token {
|
||||
int token;
|
||||
SemInfo seminfo;
|
||||
} Token;
|
||||
|
||||
|
||||
typedef struct LexState {
|
||||
int current; /* current character (charint) */
|
||||
int linenumber; /* input line counter */
|
||||
int lastline; /* line of last token `consumed' */
|
||||
Token t; /* current token */
|
||||
Token lookahead; /* look ahead token */
|
||||
struct FuncState *fs; /* `FuncState' is private to the parser */
|
||||
struct lua_State *L;
|
||||
ZIO *z; /* input stream */
|
||||
Mbuffer *buff; /* buffer for tokens */
|
||||
TString *source; /* current source name */
|
||||
char decpoint; /* locale decimal point */
|
||||
} LexState;
|
||||
|
||||
|
||||
LUAI_FUNC void luaX_init (lua_State *L);
|
||||
LUAI_FUNC void luaX_setinput (lua_State *L, LexState *LS, ZIO *z,
|
||||
TString *source);
|
||||
LUAI_FUNC TString *luaX_newstring (LexState *LS, const char *str, size_t l);
|
||||
LUAI_FUNC void luaX_next (LexState *ls);
|
||||
LUAI_FUNC void luaX_lookahead (LexState *ls);
|
||||
LUAI_FUNC void luaX_lexerror (LexState *ls, const char *msg, int token);
|
||||
LUAI_FUNC void luaX_syntaxerror (LexState *ls, const char *s);
|
||||
LUAI_FUNC const char *luaX_token2str (LexState *ls, int token);
|
||||
|
||||
|
||||
#endif
|
128
src/lua/llimits.h
Normal file
128
src/lua/llimits.h
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
** $Id: llimits.h,v 1.69 2005/12/27 17:12:00 roberto Exp $
|
||||
** Limits, basic types, and some other `installation-dependent' definitions
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef llimits_h
|
||||
#define llimits_h
|
||||
|
||||
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
|
||||
typedef LUAI_UINT32 lu_int32;
|
||||
|
||||
typedef LUAI_UMEM lu_mem;
|
||||
|
||||
typedef LUAI_MEM l_mem;
|
||||
|
||||
|
||||
|
||||
/* chars used as small naturals (so that `char' is reserved for characters) */
|
||||
typedef unsigned char lu_byte;
|
||||
|
||||
|
||||
#define MAX_SIZET ((size_t)(~(size_t)0)-2)
|
||||
|
||||
#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2)
|
||||
|
||||
|
||||
#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */
|
||||
|
||||
/*
|
||||
** conversion of pointer to integer
|
||||
** this is for hashing only; there is no problem if the integer
|
||||
** cannot hold the whole pointer value
|
||||
*/
|
||||
#define IntPoint(p) ((unsigned int)(lu_mem)(p))
|
||||
|
||||
|
||||
|
||||
/* type to ensure maximum alignment */
|
||||
typedef LUAI_USER_ALIGNMENT_T L_Umaxalign;
|
||||
|
||||
|
||||
/* result of a `usual argument conversion' over lua_Number */
|
||||
typedef LUAI_UACNUMBER l_uacNumber;
|
||||
|
||||
|
||||
/* internal assertions for in-house debugging */
|
||||
#ifdef lua_assert
|
||||
|
||||
#define check_exp(c,e) (lua_assert(c), (e))
|
||||
#define api_check(l,e) lua_assert(e)
|
||||
|
||||
#else
|
||||
|
||||
#define lua_assert(c) ((void)0)
|
||||
#define check_exp(c,e) (e)
|
||||
#define api_check luai_apicheck
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef UNUSED
|
||||
#define UNUSED(x) ((void)(x)) /* to avoid warnings */
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef cast
|
||||
#define cast(t, exp) ((t)(exp))
|
||||
#endif
|
||||
|
||||
#define cast_byte(i) cast(lu_byte, (i))
|
||||
#define cast_num(i) cast(lua_Number, (i))
|
||||
#define cast_int(i) cast(int, (i))
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** type for virtual-machine instructions
|
||||
** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
|
||||
*/
|
||||
typedef lu_int32 Instruction;
|
||||
|
||||
|
||||
|
||||
/* maximum stack for a Lua function */
|
||||
#define MAXSTACK 250
|
||||
|
||||
|
||||
|
||||
/* minimum size for the string table (must be power of 2) */
|
||||
#ifndef MINSTRTABSIZE
|
||||
#define MINSTRTABSIZE 32
|
||||
#endif
|
||||
|
||||
|
||||
/* minimum size for string buffer */
|
||||
#ifndef LUA_MINBUFFER
|
||||
#define LUA_MINBUFFER 32
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef lua_lock
|
||||
#define lua_lock(L) ((void) 0)
|
||||
#define lua_unlock(L) ((void) 0)
|
||||
#endif
|
||||
|
||||
#ifndef luai_threadyield
|
||||
#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** macro to control inclusion of some hard tests on stack reallocation
|
||||
*/
|
||||
#ifndef HARDSTACKTESTS
|
||||
#define condhardstacktests(x) ((void)0)
|
||||
#else
|
||||
#define condhardstacktests(x) x
|
||||
#endif
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user