Fun with Lua

Introduction

LuaForge is the major repository for user-contributed tools in sourcecode and compiled versions, and includes LuaBinaries (project homepage), which are pre-compiled Lua libraries and executables. lua52.exe is the console-based interpreter, wlua52.exe is similar to lua52.exe but provides no console output (which means you'll need to write a GUI to interact with the invisible interpreter); luac5.2.exe compiles a Lua source file into bytecode; bin2c5.1.exe turns Lua bytecode into C (?). Those command-line executables are just clients of the lua*.dll libraries, just like sqlite3.exe is the command-line version of the sqlite.dll.

Alternatively, Lua for Windows is an easy-to-use distribution of Lua packed with several useful libraries. Lua for Windows installs Lua language, SciTE based Lua IDE and Lua modules to the directory of you choice at install time. Lua for Windows and it's modules all depend on the MSVC++ 2005 runtime library.

The lua-users wiki lists many user-contributed addons for Lua, including tools, libraries, full distributions, and binaries for several platforms. You can get support through the Lua mailing-list.

Setup

Here's how to install Lua on a Debian host:

apt-get update

apt-get install lua5.2

which lua

Hello, world!

Here's a simple Lua script that you can use to check that the interpreter works:

-- This is a comment
print ("Hello World!")

Note: The shebang line is not needed in Windows, provided the OS can locate the interpreter (eg. lua5.1.exe).

To run the script, simply call the interpreter with the script name as parameter:

lua5.1.exe hello.lua

On Linux, alternatively, add the shebang line and make the script executable, respectively:

#!/usr/bin/lua
 
chmod +x hello.lua

Commenting a whole block

--[[
whole
block
commented
out
--]]

Declaring and filling a table

t = {}
t["foo"] = 123
print t["foo"]

Alternatively:

t = {foo = 123, bar = "456"}
t.foo = 123
print t.foo

Looping through a table

for key,value in pairs(t) do
    print(key,value)
end

Alternatively, this can be done in a single line:

for key,value in pairs(t) do print(key, value) end

Modules

Installing binary modules

Here's how to install the LuaRocks package manager on Debian/Ubuntu, and install ready-to-use modules:

  1. apt-get install luarocks
  2. luarocks install mypackage

Note: LuaRocks has a lot of dependencies:

The following extra packages will be installed:
  autotools-dev binutils cpp cpp-4.6 gcc gcc-4.6 gcc-4.6-base libc-dev-bin libc6-dev libgmp10 libgomp1 libltdl-dev libltdl7
  liblua5.1-0 liblua5.1-0-dev libmpc2 libmpfr4 libreadline-dev libreadline6-dev libtinfo-dev libtool linux-libc-dev lua5.1
  manpages-dev pkg-config zip
 
Suggested packages:
  binutils-doc cpp-doc gcc-4.6-locales gcc-multilib make autoconf automake1.9 flex bison gdb gcc-doc libmudflap0-4.6-dev
  gcc-4.6-doc libgcc1-dbg libgomp1-dbg libquadmath-dbg libmudflap0-dbg binutils-gold glibc-doc libtool-doc automaken
  gfortran fortran95-compiler gcj
 
The following NEW packages will be installed:
  autotools-dev binutils cpp cpp-4.6 gcc gcc-4.6 gcc-4.6-base libc-dev-bin libc6-dev libgmp10 libgomp1 libltdl-dev libltdl7
  liblua5.1-0 liblua5.1-0-dev libmpc2 libmpfr4 libreadline-dev libreadline6-dev libtinfo-dev libtool linux-libc-dev lua5.1
  luarocks manpages-dev pkg-config zip
 
0 upgraded, 27 newly installed, 0 to remove and 0 not upgraded.
Need to get 22.2 MB of archives.
After this operation, 55.2 MB of additional disk space will be used.

Testing

Here's a simply module that you can use to check that you can successfully compile and load a module:

/* dummy.c */
#include <stdio.h>
#include "lua.h"
 
int luaopen_dummy (lua_State *L) {
    puts("Hello from dummy");
    return 0;
}

Here's how to compile it. You must first provide the Lua source files:

gcc -fpic -I/usr/src/lua-5.1.4/src -shared -Wl,-E,-soname,libdummy.so -o libdummy.so dummy.c

And here's how to load it in Lua:

lua -l libdummy

LuaSocket

After compiling LuaSocket, here's how to install and load it:

  1. mkdir -p /usr/local/lib/lua/5.1.4/mime
    mkdir -p /usr/local/lib/lua/5.1.4/socket
    wget http://srv/socket.2.0.2.so
    wget http://srv/mime.1.0.2.so
    mv socket.2.0.2.so /usr/local/lib/lua/5.1.4/socket/core.so
    mv mime.1.0.2.so /usr/local/lib/lua/5.1.4/mime/core.so
  2. mkdir -p /usr/local/share/lua/5.1.4/socket
    wget http://srv/luasocket.scripts.tar
    tar xvf luasocket.scripts.tar
    mv ltn12.lua mime.lua socket.lua /usr/local/share/lua/5.1.4/
    mv http.lua tp.lua ftp.lua smtp.lua url.lua /usr/local/share/lua/5.1.4/socket
  3. vi /etc/profile
    export LUA_PATH='/usr/local/share/lua/5.1.4/?.lua;?.lua'
    export LUA_CPATH='/usr/local/lib/lua/5.1.4/?.so;?.so'
  4. cd /var/tmp/
    ./lua
    > socket = require("socket")
    > print(socket._VERSION)

Here's how to send a datagram to NetCID to display CallerID information on the user's monitor:

http://www.voip-info.org/wiki/view/Asterisk+NetCID

LuaSQL

This is a front-end to different database servers. If using SQLite3, you must first compile SQLite3 from www.sqlite.org, then compile LuaSQL for SQLite3. The output file sqlite3.so combines SQLite3 and LuaSQL in a single binary file.

Here's the config file and Makefile to compile LuaSQL and include libsqlite3.o.

/usr/src/luasql-2.1.1# cat config
 
T=sqlite3
LIBNAME= $T.so
 
PREFIX = /usr/local
LUA_INC= /usr/src/lua-5.1.4
LUA_VERSION_NUM= 501
 
INCS= -I$(LUA_INC)
 
LIB_OPTION = -shared -Wl,-soname,$(LIBNAME)
 
#DRIVER_LIBS=-L/usr/src/sqlite-3.7.3/preprocessed -lsqlite3
DRIVER_INCS = -I/usr/src/sqlite-3.7.3/preprocessed
 
CFLAGS= -O2 -Wall -ansi
 
/usr/src/luasql-2.1.1# cat Makefile
V= 2.1.1
CONFIG= ./config
 
include $(CONFIG)
 
OBJS=src/luasql.o src/ls_$T.o
 
src/$(LIBNAME): $(OBJS)
        $(CC) $(CFLAGS) $(LIB_OPTION) -o $@ $(OBJS) /usr/src/sqlite-3.7.3/preprocessed/sqlite3.o
 
$(OBJS):
        $(CC) $(CFLAGS) $(INCS) $(DRIVER_INCS) -c $*.c -o $@

Put sqlite3.so in its ./luasql/ directory where Lua can find it. Next, here's how to use it:

require "luasql.sqlite3"
 
env = luasql.sqlite3()
conn = env:connect("testsqlite.db3")
 
assert(conn:execute("create table if not exists tbl1(one, two)"))
assert(conn:execute("insert into tbl1 values('hello!',10)"))
assert(conn:execute("insert into tbl1 values('goodbye',20)"))
 
conn:close()
env:close()

SQLite

Here's how to install SQLite and the Lua package required to use it from Lua:

  1. apt-get update
  2. Check that the SQLite library is installed: dpkg -l | grep sqlite ; If not installed: apt-get install libsqlite3-0
  3. Install the shared library : apt-get install libsqlite3-dev
  4. Install the command-line interface: apt-get install sqlite3
  5. apt-get install luarocks (Rocks are packages containing Lua modules, and Luarocks is a package manager; Luarocks will install other packages such as the liblua5.1-0 interpreter)
  6. Test that Lua is installed by simply typing "lua" at the command prompt, and hitting CTRL+C to exit
  7. luarocks install lsqlite3 SQLITE_INCDIR=/tmp/sqlite3/sqlite-amalgamation-3080200
  8. Test with the following script:

    #!/usr/bin/env lua
    sqlite3 = require('lsqlite3')

    local db = sqlite3.open('requests.db')
    db:close()
     
  9. Chmod +x test.lua ; ./test.lua

HTTP client

There are different ways to have a Lua script connect to an HTTP server:

LuaCURL (easy interface; luacurl 1.2.1 is single file with no makefile: luacurl.c, and requires downloading Libcurl; written by Alexander Marinov and Enrico Tassi)

lua-curl (richer; written by Jürgen Hötzel)

Lua-httpd (very basic)

webGet (Windows only)

HTTP Front-end

Here's how to run a server that will open a TCP socket, wait for HTTP queries, use a regex to extract bits from the query, forward the SQL query to the SQLite back-end, and return results to the client:

Here's how to install this as a Windows Service:

How to prevent the server from duplicating the socket, ie. only one client must be able to connect and work with the socket at any time?

In , luasocket-2.0.2-lua-5.1.2-Win32-vc8.zip, no trace of \lib\:

 

http://w3.impa.br/~diego/software/luasocket/

"it's actually quite difficult to write network code without multithreading. given that networking is largely unreliable speed-wise (to the tune of several milliseconds in bad cases) you really don't want to tie up the cpu waiting for a packet to arrive. normally the networking layer runs continuously in the background, doing all the painful waiting around for packets for you, and then you query it for useful information. however, this requires multithreading." http://www.devmaster.net/forums/showthread.php?t=5890

Scripting with Lua

There are multiple ways to run Lua scripts:

Through CGI

For security reason, Nginx doesn't recommend running scripts through CGI but it can be done.

Alternative : thttpd or mini-httpd + Haserl, or uwsgi with CGI support.

"While nginx is a fine piece of machinery, do you really need such a tight integration and its added complexity? CGI is looked down at, but its simplicity and portability cannot be beaten. A combination of, say, Acme Labs' thttpd and Lua scripts could be a winner, at one tenth of nginx footprint."

http://lua-users.org/lists/lua-l/2012-09/msg00438.html

"And if you really think [parsing] is going to make any practical difference, package the entire enchilada into one tight little executable with srclua [1] or such."

http://lua-users.org/lists/lua-l/2012-09/msg00453.html

mini-httpd + Haserl

Why use Haserl instead of straight CGI?

Let's go:

  1. apt-get update
  2. apt-get install mini-http
  3. apt-get install haserl
  4. mkdir -p /tmp/mini-httpd/www
  5. mkdir /tmp/mini-httpd/cgi-bin
  6. vi /etc/mini-httpd.conf

    host=0.0.0.0
    port=9999
    user=nobody
    cgipat=**.lua|**.cgi
    charset=iso-8859-1
    data_dir=/tmp/mini-httpd
    logfile=/tmp/mini-httpd/mini-httpd.log
    pidfile=/var/run/mini-httpd.pid

    #dir
    #chroot/nochroot
     
  7. vi /etc/default/mini-httpd.conf: "START=1" if launching the server through its init.d script
  8. vi hello.lua

    #!/usr/bin/haserl --shell=lua
    content-type: text/plain

    Both work:
    <!-- % io.write ("Hello World" ) %-->
    <%= "Hello World" %>
     
  9. chown nobody.nogroup /tmp/mini-httpd/cgi-bin/hello.lua
  10. chmod +x /tmp/mini-httpd/cgi-bin/hello.lua
  11. /etc/init.d/mini-httpd start
  12. Aim your browser at http://srv:9999/cgi-bin/hello.lua

/usr/share/doc/mini-httpd

mini_httpd  [-C configfile] [-p port] [-d dir] [-dd data_dir] [-c cgipat] [-u user] [-h hostname] [-r] [-v] [-l logfile] [-i pidfile] [-T charset] [-P P3P] [-M maxage] [-S] [-E certfile] [-Y cipher] [-D] [-V]

"/usr/sbin/mini-httpd: started as root without requesting chroot(), warning only"

Can CGI scripts be restricted to ./cgi-bin?
How to disable directory listing?

Remove the read permission bit for the user under which mini_httpd is running, eg:

chmod o-r directory

(In this example, assuming that mini_httpd isn't running as a user or group member of that directory.)

How to run chroot?

Make sure any shells, utilities, and config files used by your CGI programs and scripts are available.  [...] However, one thing you should do is tell syslogd about the chroot tree, so that mini_httpd can still  generate  syslog  messages.   Check  your  system's  syslodg  man  page  for  how  to  do  this.  In FreeBSD you would put something like this in /etc/rc.conf:

           syslogd_flags="-l /usr/local/www/data/dev/log"

Substitute in your own chroot tree's pathname, of course.  Don't worry about creating the log socket, syslogd  wants  to  do that  itself.   (You  may  need to create the dev directory.)  In Linux the flag is -a instead of -l, and there may be other differences.

How to password-protect directory?

Basic Authentication uses a password file called ".htpasswd", in the directory to be protected.  This file is  formatted  as the familiar colon-separated username/encrypted-password pair, records delimited by newlines.  The protection does not carry over to subdirectories. The utility program htpasswd(1) is included to help create and modify .htpasswd files.

/usr/bin/htpasswd

How to handle errors?

mini_httpd  lets you define your own custom error pages for the various HTTP errors.  There's a separate file for each error number, all stored in one special directory.  The directory name is "errors", at the top of the  web  directory  tree.   The error  files  should be named "errNNN.html", where NNN is the error number.  So for example, to make a custom error page for the authentication failure error, which is number 401, you would put your HTML into the file  "errors/err401.html".   If  no custom error file is found for a given error number, then the usual built-in error page is generated.

mini-httpd + WSAPI

Based on Using lua wsapi with mini-httpd

  1. apt-get install liblua5.1-wsapi1
  2. apt-get install mini-httpd
  3. vi /etc/mini-httpd.conf
  4. vi /etc/default/mini-httpd.conf
  5. mkdir /tmp/mini-httpd
  6. touch /tmp/mini-httpd/mini-httpd.log
  7. vi index.cgi
  8. chown nobody.nogroup ./index.cgi
  9. chmod +x index.cgi
  10. /etc/init.d/mini-httpd start
  11. Aim your browser at http://srv:9999/index.cgi

Through FastCGI

WSAPI and luafcgid? Note: WSAPI is to Lua what WSGI is to Python: "WSAPI is an API that abstracts the web server from Lua web applications. By coding against WSAPI your application can run on any of the supported servers and interfaces" (source)

https://github.com/mbalmer/luafcgi

Through uWSGI

More information here.

Through the Nginx ngx_lua module (a.k.a. HttpLuaModule)

Important: "unlike most other SQL databases, SQLite is serverless, which means that using SQLite directly in Nginx will block the Nginx worker processes and ruin the performance. " (source)

So it looks like if your script relies on SQLite, ngx_lua isn't a good idea and you should check the FastCGI/uWSGI options instead.

OpenResty

OpenResty is a tool that will build a Lua-capable Nginx server with additional modules. Note that, as of Jan 2013, SQLite seems unavailable as a Nginx module, so the Lua scripts require installing SQLite and the Lua module independently.
  1. apt-get install libreadline-dev libncurses5-dev libpcre3-dev libssl-dev perl make
  2. wget -c http://openresty.org/download/ngx_openresty-1.4.3.6.tar.gz
  3. tar xzvf ngx_openresty-1.4.3.6.tar.gz
  4. cd ngx_openresty-1.4.3.6/
  5. To see which options are available: ./configure --help
  6. ./configure --with-luajit --prefix=/tmp/ngx_openresty-1.4.3.6/install
  7. make
  8. make install (default: /usr/local/openresty/)

If you want to find where the binaries will be installed, use "make -n install"; Use "make install DESTDIR=TMP && tree TMP" to install it to a given directory.

Note: OpenResty doesn't include support for SQLite, because "using SQLite directly in Nginx will block the Nginx worker processes and ruin the performance." (source)

Manually

If you already have Nginx installed, run "nginx -V" to check if it was compiled with the the ngx_lua module.

"You can install it from source by compiling the lua-nginx-module with your existing Nginx. If you chose that path you will also need a Lua interpreter. LuaJIT-2.0.0 is recommended."

http://blog.cloudflare.com/pushing-nginx-to-its-limit-with-lua

"The ngx_lua module is for running Lua code directly in the nginx webserver. It is possible to run entire Lua applications in this way but this is not the specific target of that module. Actually, some of the module directives specifically should not be used with long running or complex routines. You will need to recompile Nginx with this module as you cannot just download an Nginx module and use it like that."

"BTW openresty is just regular Nginx with some 3rd party modules bundled in including ngx_lua and the people behind openresty are the same behind ngx_lua"

http://stackoverflow.com/questions/9434448/running-lua-under-nginx-writing-a-website-with-lua

As an alternative to the run-of-the-mill Lua compiler, you can try LuaJIT.

Here's how to compile Nginx to include the ngx_lua module:

  1. Download and install the following parts:
    1. Either Lua or LuaJIT and its include/lib
    2. ngx_devel_kit: wget -c https://github.com/simpl/ngx_devel_kit/archive/v0.2.19.tar.gz
    3. ngx_lua: https://github.com/chaoslawful/lua-nginx-module/tags
    4. The Nginx source: wget -c http://nginx.org/download/nginx-1.5.8.tar.gz
  2. Compile and install thusly:

    export LUA_LIB=/usr/lib/arm-linux-gnueabi
    export LUA_INC=/usr/include/lua5.1

    ./configure --prefix=/opt/nginx --add-module=../ngx_devel_kit-0.2.19 --add-module=../lua-nginx-module-0.9.4
    make -j2
    make install
  3.  

Mongoose

Mongoose is a light cross-platform web server that can be compiled to support Lua and SQLite:

  1. apt-get install git
  2. cd /tmp
  3. git clone https://github.com/cesanta/mongoose.git
  4. cd mongoose/build
  5. make mongoose-lua-sqlite
  6. Run the Mongoose binary: ./mongoose-lua-sqlite
  7. Save this sample as test.mg.lua in the same directory:

    mg.write('HTTP/1.0 200 OK\r\n', 'Content-Type: text/plain\r\n', '\r\n')
    mg.write(os.date("%A"))
     
  8. Hit the server: http://srv/test.mg.lua
  9. Next, add this to check that SQLite works:

    local db = sqlite3.open('requests.db')
    db:close()

April 2014: The build process changed

  1. Download and untar the Mongoose 5.4 source code
  2. Within the Mongoose directory, download and untar the Lua source code (eg. /tmp/Mongoose-5.4/lua-5.2.3/src)
  3. Edit examples/Makefile to enable Lua
  4. cd examples
  5. make server

Note:

Mongoose.conf example

enable_directory_listing no
hide_files_patterns .htaccess
#DEPRECATED? access_log_file mongoose.access.log
#DEPRECATED error_log_file mongoose.error.log
run_as_user nobody
cgi_pattern /var/local/mongoose/cgi-bin/*.cgi
#Per-directory .htpasswd is alternative to global_auth_file
#listening_port 80
 
#If using .htpasswd
auth_domain acme.com
 
document_root /var/local/mongoose/www.

Mongoose init.d script

#! /bin/sh
### BEGIN INIT INFO
# Provides:          mongoose
# Required-Start:    $syslog $time $remote_fs
# Required-Stop:     $syslog $time $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Mongoose web server
# Description:       Debian init script for the Mongoose web server
### END INIT INFO
 
PATH=/bin:/usr/bin:/sbin:/usr/sbin
DAEMON=/usr/sbin/mongoose-lua-sqlite
PIDFILE=/var/run/mongoose.pid
 
test -x $DAEMON || exit 0
 
. /lib/lsb/init-functions
 
case "$1" in
  start)
        log_daemon_msg "Starting Mongoose web server" "mongoose"
        start_daemon -p $PIDFILE $DAEMON &
        log_end_msg $?
    ;;
  stop)
        log_daemon_msg "Stopping Mongoose web server" "Mongoose"
        killproc -p $PIDFILE $DAEMON
        log_end_msg $?
    ;;
  force-reload|restart)
    $0 stop
    $0 start
    ;;
  status)
    status_of_proc -p $PIDFILE $DAEMON atd && exit 0 || exit $?
    ;;
  *)
    echo "Usage: /etc/init.d/mongoose {start|stop|restart|force-reload|status}"
    exit 1
    ;;
esac
 
exit 0

Running Lua scripts

https://github.com/cesanta/mongoose/tree/master/examples/lua

Here's hello.lp:

HTTP/1.0 200 OK
Content-Type: text/plain
 
<?
mg.write("Hello, world!", "\n")
?>

Here's how to play with SQLite:

HTTP/1.0 200 OK
Content-Type: text/plain
 
<?
local db = sqlite3.open('test.db')
 
-- Can be slow if writing to an SD card formated in ext4
db:exec[[
  BEGIN TRANSACTION;
  CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, content);
  INSERT INTO test VALUES (NULL, 'Hello World');
  INSERT INTO test VALUES (NULL, 'Hello Lua');
  INSERT INTO test VALUES (NULL, 'Hello Sqlite3')
  COMMIT;
]]
 
for row in db:nrows("SELECT * FROM test") do
  print(row.id, row.content)
end
db:close()
?>

Note: If SQLite is noticeably slower than other systems, check if the filesystem is ext4.

Examples are available in the lsqlite LuaRocks package (eg. /usr/local/lib/luarocks/rocks/lsqlite3/0.9.1-2/examples/).

Questions

http://cesanta.com/#docs,Mongoose.md

DONE mongoose.conf : Format can be either "A B" or ""A=B"

NO Are Lua scripts run through CGI when compiled with "make mongoose-lua"?
NO Is it safe to locate and run cgi-bin scripts from within the docroot?
What should file access rights be for CGI scripts? Is 500 OK?

YES Is it possible to mix Lua with HTML?

docs/LuaSqlite.md doesn't mention Lua scripts with .mg.lua extension: Are HTML with embedded Lua code (.lp) still available in addition to Lua scripts with .mg.lua extension? Which way do you recommend?

Is using LuaRocks OK to install Lua modules and access them from Lua scripts in Mongoose?

What is the difference between lua and luac?

Can Mongoose be launched at boot time as a service? "Mongoose does not detach from terminal." says the docs

Any tips about how to handle HTML forms safely, and generally, about running Mongoose safely, including Lua scripting?

Infos about running Mongoose safely, including Lua scripting

.htaccess: What is a realm? This doesn't work: ./mongoose-lua-sqlite -A .htpasswd 192.168.0.10 joe test -> joe:192.168.0.10:c8b1228323d9839b089a4ebd57c131cf

How to handle 404 instead of just displaying "404 Not Found"?

How to log access/error? Even with "error_log_file mongoose.error.log" in mongoose.conf, no file is created when a 404 occurs

Xavante

Here's how to install the light-weight Xavante server which is written in Lua so you have everything you need to write a low-scale web server to run Lua scripts:

  1. Download and install Lua for Windows
  2. Download the LuaRocks for Lua for Windows ZIP file
  3. Unzip the LuaRocks package directly at the root of the Lua for Windows installation directory (C:\Program Files\Lua\5.1\).
  4. Next, install Xavante using LuaRocks: luarocks install xavante
  5. The "xavante" package installs Xavante as a library. To run Xavanteas an application, install WSAPI: luarocks install wsapi-xavante
  6. cd "C:\Program Files\Lua\5.1\rocks\wsapi\X.X.X\samples\", and run

    wsapi (If 8080 isn't available, run eg. wsapi -p9999)
     
  7. Next, aim your browser at http://localhost:8080/hello.lua

Strings

Extracting first token in space-separated items

exec = line:sub(1,string.find(line,"%s")-1)

Extracting space- and comma-separated tokens

for token in string.gmatch(line, "[^%s,]+") do

    print(token)

end

Extracting filename from path

filename=string.gsub(fullfilename, "(.*/)(.*)", "%2")

Extracting multiple tokens

page = '<span>item1</span><br>item2<br>item3<br><i>'

for a,b in string.gmatch(page, '<span>.-</span><br>(.-)<br>(.-)<br><i>') do

        stuff = a .. b .. "\n========\n"

        print(stuff)

end

Networking

Downloading web pages

http = require("socket.http")

mypage = http.request("http://www.google.com")

Files

Check the size of a file

function fsize (file)
        local current = file:seek()      -- get current position
        local size = file:seek("end")    -- get file size
        file:seek("set", current)        -- restore position
        return size
end
 
fh = assert(io.open("/full/path/to/file","r"))
print(fsize(fh))
fh:close()

Read from a text file

local file = assert(io.open ("myfile.txt","r"))
data = file:read("*a")
print(data)
file:close()

Alternatively, use io.lines:

for line in io.lines('myfile.txt') do
        print(line)
end

Write to a text file

local file = assert(io.open ("myfile.txt","w"))
file:write("Blah\n")
file:close()

Read file and extract tokens

libs = io.open("myfile.txt","r")
for line in libs:lines() do
    -- finds all occurences of "some text," at the beginning of a line
    for token in string.gmatch(line, "[^%s,]+") do
        print(token)
    end
end
libs:close()

Here's an example that extract all URL's from a text file:

for line in data:lines() do
        for w in string.gmatch(line, '<a href="(/somedir/[%w-]+%.php)">') do
                print(w)
        end
end

Troubleshooting

If you get an error message like "Unable to resolve symbol" when loading a module, try compiling and loading this simple module:

/* dummy.c -- a minimal Lua library for testing dynamic loading */
#include <stdio.h>
#include "lua.h"
int luaopen_dummy (lua_State *L) {
    puts("Hello from dummy");
    return 0;
}

Compile this as a shared library: cc -shared -fPIC -o dummy.so dummy.c

Load in in Lua thusly: lua -ldummy OR lua > print(require"dummy")

Note: The line require "dummy" looks for the function name luaopen_dummy within the shared library.

If that works, try this next:

#include <stdio.h>
#include "lua.h"
int luaopen_dummy (lua_State *L) {
 puts("Hello from dummy");
 lua_pushnil(L);
 puts("Bye from dummy");
 return 0;
}

Reading Notes: "Beginning Lua Programming" - Wrox 2007

The Lua interpreter lua51.exe just calls the Lua DLL where most of the logic live. lua51.exe can be put anywhere as long as it can find the DLL through the %PATH% env't variable.

wlua5.1.exe acts like lua51.exe, but with no console output (so a GUI is required to interact with user)

lua5.1.dll and lua51.dll: There was a disagreement about what the DLL should be called, so lua51.dll is a 'proxy' DLL referencing lua5.1.dll. Some extensions link against lua5.1.dll, some against lua51.dll.

luac5.1.exe turns Lua source files into bytecode. Since the interpreter is very fast anyway, the compiler is apparently not often used.

bin2c5.1.exe: Turns Lua scripts into C source.

All binary extensions must be linked against the same C runtime (The Lua for Windows depends on the Microsoft C runtime library MSVCRT.DLL).

Kepler = Lua-based web server

Two ways to build Lua so you can run Unix tools:

Unlike other languages, a function in Lua can return more than one value:

function ReturnArgs(Arg1, Arg2, Arg3)
    return Arg1, Arg2, Arg3
end
 
A, B, C = ReturnArgs(alpha", "bravo", "charlie")
print(A, B, C)
> alpha bravo charlie

The Lua for Windows executable looks up the DLL extensions in the \clibs subdirectory (in general, Lua uses the LUA_CPATH environment variable)

LuaRocks: For some common rocks, Windows binaries already exist. If a binary rock exists, Lua Rocks will download that rather than the source rock.

Q&A

How to end script before the end?

if true then return end

I need "sleep"

Lua is based on ANSI C, which doesn't provide a function to pause a script. Here's a C program that you can compile as a shared library:

www.troubleshooters.com/codecorn/lua/lua_lua_calls_c.htm#_Make_an_msleep_Function

Can Xavante be installed as a Windows Service?

http://luaforge.net/projects/luaservice/

What files/directories do I need to pack a self-contained Xavante server?

WSAPI vs. WSAPI-Xavante vs. Xavante?

Xavante is a module that handles HTTP requests. WSAPI is a protocol to generate HTTP responses and isn't tied to a specific, underlying web server.

wsapi.exe runs WSAPI-Xavante which binds the handler (Xavante) and the protocol (WSAPI).

What do the files do?

Downloaded the basic Windows package from luabinaries.luaforge.net lua5_1_4_Win32:

Here's the Lua for Windows package (C:\Program Files\Lua\5.1):

Resources