mirror of
https://github.com/tio/tio.git
synced 2026-05-01 14:57:59 +02:00
Overhaul Lua API
Lua API moved into a tio library table and names adjusted to Lua stdlib style. Regex in expect() replaced with Lua patterns so binary data can be handled. New tio.alwaysecho variable allows enabling and disabling echo to console. Read and write functions now manage complex retry and timeout logic internally, giving the user a simple "nil if fail" API like the rest of Lua. exit() was removed, os.exit() already exists in the Lua standard library.
This commit is contained in:
parent
8f33cff6ea
commit
114b69b68a
9 changed files with 318 additions and 465 deletions
94
README.md
94
README.md
|
|
@ -288,12 +288,12 @@ $ cat data.bin | tio /dev/ttyUSB0
|
||||||
|
|
||||||
Manipulate modem lines on connect:
|
Manipulate modem lines on connect:
|
||||||
```
|
```
|
||||||
$ tio --script "set{DTR=high,RTS=low}; msleep(100); set{DTR=toggle,RTS=toggle}" /dev/ttyUSB0
|
$ tio --script "tio.set{DTR=high,RTS=low}; tio.msleep(100); tio.set{DTR=toggle,RTS=toggle}" /dev/ttyUSB0
|
||||||
```
|
```
|
||||||
|
|
||||||
Pipe command to serial device and wait for line response within 1 second:
|
Pipe command to serial device and wait for line response within 1 second:
|
||||||
```
|
```
|
||||||
$ echo "*IDN?" | tio /dev/ttyACM0 --script "expect('\r\n', 1000)" --mute
|
$ echo "*IDN?" | tio /dev/ttyACM0 --script "tio.expect('\r\n', 1000)" --mute
|
||||||
KORAD KD3305P V4.2 SN:32475045
|
KORAD KD3305P V4.2 SN:32475045
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -365,12 +365,12 @@ color = 11
|
||||||
[svf2]
|
[svf2]
|
||||||
device = /dev/ttyUSB0
|
device = /dev/ttyUSB0
|
||||||
baudrate = 9600
|
baudrate = 9600
|
||||||
script = expect("login: "); write("root\n"); expect("Password: "); write("root\n")
|
script = tio.expect("login: "); tio.write("root\n"); tio.expect("Password: "); tio.write("root\n")
|
||||||
color = 12
|
color = 12
|
||||||
|
|
||||||
[esp32]
|
[esp32]
|
||||||
device = /dev/serial/by-id/usb-0403_6014-if00-port0
|
device = /dev/serial/by-id/usb-0403_6014-if00-port0
|
||||||
script = set{DTR=high,RTS=low}; msleep(100); set{DTR=low,RTS=high}; msleep(100); set{RTS=low}
|
script = tio.set{DTR=high,RTS=low}; tio.msleep(100); tio.set{DTR=low,RTS=high}; tio.msleep(100); tio.set{RTS=low}
|
||||||
script-run = once
|
script-run = once
|
||||||
color = 13
|
color = 13
|
||||||
|
|
||||||
|
|
@ -395,72 +395,80 @@ Another more elaborate configuration file example is available [here](examples/c
|
||||||
|
|
||||||
Tio suppots Lua scripting to easily automate interaction with the tty device.
|
Tio suppots Lua scripting to easily automate interaction with the tty device.
|
||||||
|
|
||||||
In addition to the Lua API tio makes the following functions available:
|
In addition to the standard Lua API tio makes the following functions
|
||||||
|
and variables available:
|
||||||
|
|
||||||
```
|
|
||||||
expect(string, timeout)
|
#### `tio.expect(pattern, timeout)`
|
||||||
Expect string - waits for string to match or timeout before continueing.
|
|
||||||
Supports regular expressions. Special characters must be escaped with '\\'.
|
Waits for the Lua pattern to match or timeout before continuing.
|
||||||
Timeout is in milliseconds, defaults to 0 meaning it will wait forever.
|
Timeout is in milliseconds, defaults to 0 meaning it will wait forever.
|
||||||
|
|
||||||
Returns 1 on successful match, 0 on timeout, or -1 on error.
|
Returns the captures from the pattern or `nil` on timeout.
|
||||||
|
|
||||||
On successful match it also returns the match string as second return value.
|
#### `tio.read(size, timeout)`
|
||||||
|
|
||||||
read(size, timeout)
|
Read up to `size` bytes from serial device. If timeout is 0 or not provided it
|
||||||
Read from serial device. If timeout is 0 or not provided it will wait
|
will wait forever until data is ready to read.
|
||||||
|
|
||||||
|
Returns a string up to `size` bytes long on success and `nil` on timeout.
|
||||||
|
|
||||||
|
#### `tio.readline(timeout)`
|
||||||
|
|
||||||
|
Read line from serial device. If timeout is 0 or not provided it will wait
|
||||||
forever until data is ready to read.
|
forever until data is ready to read.
|
||||||
|
|
||||||
Returns number of bytes read on success, 0 on timeout, or -1 on error.
|
Returns a string on success and `nil` on timeout. On timeout a partially read
|
||||||
|
line may be returned as a second return value.
|
||||||
|
|
||||||
On success, returns read string as second return value.
|
#### `tio.write(string)`
|
||||||
|
|
||||||
read_line(timeout)
|
|
||||||
Read line from serial device. If timeout is 0 or not provided it will
|
|
||||||
wait forever until data is ready to read.
|
|
||||||
|
|
||||||
Returns number of bytes read on success, 0 on timeout, or -1 on error.
|
|
||||||
|
|
||||||
On success, returns the string that was read as second return value.
|
|
||||||
Also emits a single timestamp to stdout and log file per options.timestamp
|
|
||||||
and options.log.
|
|
||||||
|
|
||||||
write(string)
|
|
||||||
Write string to serial device.
|
Write string to serial device.
|
||||||
|
|
||||||
Returns number of bytes written on success or -1 on error.
|
Returns the `tio` table.
|
||||||
|
|
||||||
|
#### `tio.send(file, protocol)`
|
||||||
|
|
||||||
send(file, protocol)
|
|
||||||
Send file using x/y-modem protocol.
|
Send file using x/y-modem protocol.
|
||||||
|
|
||||||
Protocol can be any of XMODEM_1K, XMODEM_CRC, YMODEM.
|
Protocol can be any of `XMODEM_1K`, `XMODEM_CRC`, `YMODEM`.
|
||||||
|
|
||||||
|
#### `tio.ttysearch()`
|
||||||
|
|
||||||
tty_search()
|
|
||||||
Search for serial devices.
|
Search for serial devices.
|
||||||
|
|
||||||
Returns a table of number indexed tables, one for each serial device
|
Returns a table of number indexed tables, one for each serial device found.
|
||||||
found. Each of these tables contains the serial device information accessible
|
Each of these tables contains the serial device information accessible via the
|
||||||
via the following string indexed elements "path", "tid", "uptime", "driver",
|
following string indexed elements "path", "tid", "uptime", "driver",
|
||||||
"description".
|
"description".
|
||||||
|
|
||||||
Returns nil if no serial devices are found.
|
Returns `nil` if no serial devices are found.
|
||||||
|
|
||||||
set{line=state, ...}
|
#### `tio.set{line=state, ...}`
|
||||||
Set state of one or multiple tty modem lines.
|
Set state of one or multiple tty modem lines.
|
||||||
|
|
||||||
Line can be any of DTR, RTS, CTS, DSR, CD, RI
|
Line can be any of `DTR`, `RTS`, `CTS`, `DSR`, `CD`, `RI`
|
||||||
|
|
||||||
State is high, low, or toggle.
|
State is `high`, `low`, or `toggle`.
|
||||||
|
|
||||||
|
#### `tio.sleep(seconds)`
|
||||||
|
|
||||||
sleep(seconds)
|
|
||||||
Sleep for seconds.
|
Sleep for seconds.
|
||||||
|
|
||||||
msleep(ms)
|
#### `tio.msleep(ms)`
|
||||||
Sleep for miliseconds.
|
|
||||||
|
Sleep for milliseconds.
|
||||||
|
|
||||||
|
#### `tio.alwaysecho`
|
||||||
|
|
||||||
|
A boolean value, defaults to `true`.
|
||||||
|
|
||||||
|
If `tio.alwaysecho` is `false`, the result of `tio.read`, `tio.readline` or
|
||||||
|
`tio.expect` will only be returned from the function and not logged or printed.
|
||||||
|
|
||||||
|
If `tio.alwaysecho` is set to `true`, reading functions also emit a single
|
||||||
|
timestamp to stdout and log file per `options.timestamp` and `options.log`.
|
||||||
|
|
||||||
exit(code)
|
|
||||||
Exit with exit code.
|
|
||||||
```
|
|
||||||
|
|
||||||
## 4. Installation
|
## 4. Installation
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ color = 13
|
||||||
[esp32]
|
[esp32]
|
||||||
device = /dev/ttyUSB0
|
device = /dev/ttyUSB0
|
||||||
color = 14
|
color = 14
|
||||||
script = set{DTR=high,RTS=low}; msleep(100); set{DTR=low,RTS=high}; msleep(100); set{RTS=low}
|
script = tio.set{DTR=high,RTS=low}; tio.msleep(100); tio.set{DTR=low,RTS=high}; tio.msleep(100); tio.set{RTS=low}
|
||||||
script-run = always
|
script-run = always
|
||||||
|
|
||||||
[buspirate]
|
[buspirate]
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,13 @@ local logins = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
local found, match_str = expect("\\w+- login:", 10)
|
local hostname = tio.expect("^(%g+) login:", 10)
|
||||||
if (1 == found) then
|
if hostname then
|
||||||
local hostname = string.match(match_str, "^%w+")
|
|
||||||
local login = logins[hostname]
|
local login = logins[hostname]
|
||||||
if (nil ~= login) then
|
if (nil ~= login) then
|
||||||
write(login.username .. "\n")
|
tio.write(login.username .. "\n")
|
||||||
expect("Password:")
|
tio.expect("Password:")
|
||||||
write(login.password .. "\n")
|
tio.write(login.password .. "\n")
|
||||||
else
|
else
|
||||||
io.write("\r\nDon't know login info for " .. hostname .. "\r\n")
|
io.write("\r\nDon't know login info for " .. hostname .. "\r\n")
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
set{DTR=high, RTS=low}
|
tio.set{DTR=high, RTS=low}
|
||||||
msleep(100)
|
tio.msleep(100)
|
||||||
set{DTR=low, RTS=high}
|
tio.set{DTR=low, RTS=high}
|
||||||
msleep(100)
|
tio.msleep(100)
|
||||||
set{RTS=toggle}
|
tio.set{RTS=toggle}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
read(1000, 6000) -- initial config
|
tio.read(1000, 6000) -- initial config
|
||||||
write("\n")
|
tio.write("\n")
|
||||||
msleep(100)
|
tio.msleep(100)
|
||||||
read(650, 60) -- main menu
|
tio.read(650, 60) -- main menu
|
||||||
write("S") -- S menu
|
tio.write("S") -- S menu
|
||||||
msleep(30)
|
tio.msleep(30)
|
||||||
read(650, 60)
|
tio.read(650, 60)
|
||||||
write("t") -- Parallel Value Table
|
tio.write("t") -- Parallel Value Table
|
||||||
read(650, 60)
|
tio.read(650, 60)
|
||||||
while true do
|
while true do
|
||||||
msleep(1000)
|
tio.msleep(1000)
|
||||||
write("t")
|
tio.write("t")
|
||||||
read(650, 50) -- repeat PVT forever
|
tio.read(650, 50) -- repeat PVT forever
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
read(1000, 8000) -- read initial config
|
tio.read(1000, 8000) -- read initial config
|
||||||
write("\n")
|
tio.write("\n")
|
||||||
read(650, 100) -- main menu
|
tio.read(650, 100) -- main menu
|
||||||
write("S") -- S menu
|
tio.write("S") -- S menu
|
||||||
n = 1
|
repeat
|
||||||
while n > 0 do -- while not empty, read more
|
str = tio.readline(25)
|
||||||
n, str = read_line(25)
|
until str == nil
|
||||||
end
|
|
||||||
while true do
|
while true do
|
||||||
write("t") -- query PV table
|
tio.write("t") -- query PV table
|
||||||
msleep(880)
|
tio.msleep(880)
|
||||||
n = 1
|
repeat
|
||||||
while n > 0 do -- while not empty, read more
|
str = tio.readline(60)
|
||||||
n, str = read_line(60)
|
tio.msleep(60)
|
||||||
msleep(60)
|
until str == nil
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
io.write("Searching... ")
|
io.write("Searching... ")
|
||||||
|
|
||||||
local device = tty_search()
|
local device = tio.ttysearch()
|
||||||
|
|
||||||
io.write("done\r\n")
|
io.write("done\r\n")
|
||||||
|
|
||||||
|
|
|
||||||
58
man/tio.1.in
58
man/tio.1.in
|
|
@ -433,49 +433,40 @@ Send ctrl-t character
|
||||||
Tio suppots Lua scripting to easily automate interaction with the tty device.
|
Tio suppots Lua scripting to easily automate interaction with the tty device.
|
||||||
|
|
||||||
In addition to the standard Lua API tio makes the following functions
|
In addition to the standard Lua API tio makes the following functions
|
||||||
available:
|
and variables available:
|
||||||
|
|
||||||
.TP 6n
|
.TP 6n
|
||||||
|
|
||||||
.IP "\fBexpect(string, timeout)"
|
.IP "\fBtio.expect(pattern, timeout)"
|
||||||
Expect string - waits for string to match or timeout before continuing.
|
Waits for the Lua pattern to match or timeout before continuing.
|
||||||
Supports regular expressions. Special characters must be escaped with '\e\e'.
|
|
||||||
Timeout is in milliseconds, defaults to 0 meaning it will wait forever.
|
Timeout is in milliseconds, defaults to 0 meaning it will wait forever.
|
||||||
|
|
||||||
Returns 1 on successful match, 0 on timeout, or -1 on error.
|
Returns the captures from the pattern or nil on timeout.
|
||||||
|
|
||||||
On successful match it also returns the match string as second return value.
|
.IP "\fBtio.read(size, timeout)"
|
||||||
|
|
||||||
.IP "\fBread(size, timeout)"
|
|
||||||
Read up to size bytes from serial device. If timeout is 0 or not provided it
|
Read up to size bytes from serial device. If timeout is 0 or not provided it
|
||||||
will wait forever until data is ready to read.
|
will wait forever until data is ready to read.
|
||||||
|
|
||||||
Returns number of bytes read on success, 0 on timeout, or -1 on error.
|
Returns a string up to size bytes long on success and nil on timeout.
|
||||||
|
|
||||||
On success, returns read string as second return value. Also emits a single
|
.IP "\fBtio.readline(timeout)"
|
||||||
timestamp to stdout and log file per options.timestamp and options.log.
|
|
||||||
|
|
||||||
.IP "\fBread_line(timeout)"
|
|
||||||
Read line from serial device. If timeout is 0 or not provided it will wait
|
Read line from serial device. If timeout is 0 or not provided it will wait
|
||||||
forever until data is ready to read.
|
forever until data is ready to read.
|
||||||
|
|
||||||
Returns number of bytes read on success, 0 on timeout, or -1 on error.
|
Returns a string on success and nil on timeout. On timeout a partially read
|
||||||
|
line may be returned as a second return value.
|
||||||
|
|
||||||
On success, returns the string that was read as second return value. Also
|
.IP "\fBtio.write(string)"
|
||||||
emits a single timestamp to stdout and log file per options.timestamp
|
|
||||||
and options.log.
|
|
||||||
|
|
||||||
.IP "\fBwrite(string)"
|
|
||||||
Write string to serial device.
|
Write string to serial device.
|
||||||
|
|
||||||
Returns number of bytes written on success or -1 on error.
|
Returns the tio table.
|
||||||
|
|
||||||
.IP "\fBsend(file, protocol)"
|
.IP "\fBtio.send(file, protocol)"
|
||||||
Send file using x/y-modem protocol.
|
Send file using x/y-modem protocol.
|
||||||
|
|
||||||
Protocol can be any of XMODEM_1K, XMODEM_CRC, YMODEM.
|
Protocol can be any of XMODEM_1K, XMODEM_CRC, YMODEM.
|
||||||
|
|
||||||
.IP "\fBtty_search()"
|
.IP "\fBtio.ttysearch()"
|
||||||
Search for serial devices.
|
Search for serial devices.
|
||||||
|
|
||||||
Returns a table of number indexed tables, one for each serial device found.
|
Returns a table of number indexed tables, one for each serial device found.
|
||||||
|
|
@ -485,19 +476,26 @@ following string indexed elements "path", "tid", "uptime", "driver",
|
||||||
|
|
||||||
Returns nil if no serial devices are found.
|
Returns nil if no serial devices are found.
|
||||||
|
|
||||||
.IP "\fBset{line=state, ...}"
|
.IP "\fBtio.set{line=state, ...}"
|
||||||
Set state of one or multiple tty modem lines.
|
Set state of one or multiple tty modem lines.
|
||||||
|
|
||||||
Line can be any of DTR, RTS, CTS, DSR, CD, RI
|
Line can be any of DTR, RTS, CTS, DSR, CD, RI
|
||||||
|
|
||||||
State is high, low, or toggle.
|
State is high, low, or toggle.
|
||||||
|
|
||||||
.IP "\fBsleep(seconds)"
|
.IP "\fBtio.sleep(seconds)"
|
||||||
Sleep for seconds.
|
Sleep for seconds.
|
||||||
.IP "\fBmsleep(ms)"
|
.IP "\fBtio.msleep(ms)"
|
||||||
Sleep for milliseconds.
|
Sleep for milliseconds.
|
||||||
.IP "\fBexit(code)"
|
|
||||||
Exit with exit code.
|
.IP "\fBtio.alwaysecho"
|
||||||
|
A boolean value, defaults to true.
|
||||||
|
|
||||||
|
If tio.alwaysecho is false, the result of tio.read, tio.readline or tio.expect
|
||||||
|
will only be returned from the function and not logged or printed.
|
||||||
|
|
||||||
|
If tio.alwaysecho is set to true, reading functions also emit a single
|
||||||
|
timestamp to stdout and log file per options.timestamp and options.log.
|
||||||
|
|
||||||
.SH "CONFIGURATION FILE"
|
.SH "CONFIGURATION FILE"
|
||||||
.PP
|
.PP
|
||||||
|
|
@ -726,7 +724,7 @@ expect -i $uart "prompt> "
|
||||||
.TP
|
.TP
|
||||||
It is also possible to use tio's own simpler expect/send script functionality to e.g. automate logins:
|
It is also possible to use tio's own simpler expect/send script functionality to e.g. automate logins:
|
||||||
|
|
||||||
$ tio --script 'expect("login: "); write("root\\n"); expect("Password: "); write("root\\n")' /dev/ttyUSB0
|
$ tio --script 'tio.expect("login: "); tio.write("root\\n"); tio.expect("Password: "); tio.write("root\\n")' /dev/ttyUSB0
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
Redirect device I/O to network file socket for remote TTY sharing:
|
Redirect device I/O to network file socket for remote TTY sharing:
|
||||||
|
|
@ -747,7 +745,7 @@ $ echo "ls -la" | tio /dev/serial/by\-id/usb\-FTDI_TTL232R-3V3_FTGQVXBL\-if00\-p
|
||||||
.TP
|
.TP
|
||||||
Pipe command to serial device and wait for line response within 1 second:
|
Pipe command to serial device and wait for line response within 1 second:
|
||||||
|
|
||||||
$ echo "*IDN?" | tio /dev/ttyACM0 --script "expect('\\r\\n', 1000)" --mute
|
$ echo "*IDN?" | tio /dev/ttyACM0 --script "tio.expect('\\r\\n', 1000)" --mute
|
||||||
.TP
|
.TP
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
|
|
@ -768,7 +766,7 @@ $ tio --rs-485 --rs-485-config=RTS_ON_SEND=1,RX_DURING_TX /dev/ttyUSB0
|
||||||
.TP
|
.TP
|
||||||
Manipulate DTR and RTS lines upon first connect to reset connected microcontroller:
|
Manipulate DTR and RTS lines upon first connect to reset connected microcontroller:
|
||||||
|
|
||||||
$ tio --script "set{DTR=high,RTS=low}; msleep(100); set{RTS=toggle}" --script-run once /dev/ttyUSB0
|
$ tio --script "tio.set{DTR=high,RTS=low}; tio.msleep(100); tio.set{RTS=toggle}" --script-run once /dev/ttyUSB0
|
||||||
|
|
||||||
.SH "WEBSITE"
|
.SH "WEBSITE"
|
||||||
.PP
|
.PP
|
||||||
|
|
|
||||||
548
src/script.c
548
src/script.c
|
|
@ -20,7 +20,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <regex.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
@ -45,23 +44,87 @@
|
||||||
#define READ_LINE_SIZE 4096 // read_line buffer length
|
#define READ_LINE_SIZE 4096 // read_line buffer length
|
||||||
|
|
||||||
static int device_fd;
|
static int device_fd;
|
||||||
static char circular_buffer[MAX_BUFFER_SIZE];
|
|
||||||
static char match_string[MAX_BUFFER_SIZE];
|
|
||||||
static int buffer_size = 0;
|
|
||||||
|
|
||||||
static char script_init[] =
|
static char script_init[] =
|
||||||
"function set(arg)\n"
|
"tio.set = function(arg)\n"
|
||||||
" local dtr = arg.DTR or -1\n"
|
" local dtr = arg.DTR or -1\n"
|
||||||
" local rts = arg.RTS or -1\n"
|
" local rts = arg.RTS or -1\n"
|
||||||
" local cts = arg.CTS or -1\n"
|
" local cts = arg.CTS or -1\n"
|
||||||
" local dsr = arg.DSR or -1\n"
|
" local dsr = arg.DSR or -1\n"
|
||||||
" local cd = arg.CD or -1\n"
|
" local cd = arg.CD or -1\n"
|
||||||
" local ri = arg.RI or -1\n"
|
" local ri = arg.RI or -1\n"
|
||||||
" line_set(dtr, rts, cts, dsr, cd, ri)\n"
|
" tio.line_set(dtr, rts, cts, dsr, cd, ri)\n"
|
||||||
"end\n";
|
"end\n"
|
||||||
|
"tio.expect = function(pattern, timeout)\n"
|
||||||
|
" local str = ''\n"
|
||||||
|
" while true do\n"
|
||||||
|
" local c = tio.read(1, timeout)\n"
|
||||||
|
" if c then\n"
|
||||||
|
" str = str .. c\n"
|
||||||
|
" if string.match(str, pattern) then\n"
|
||||||
|
" return string.match(str, pattern)\n"
|
||||||
|
" end\n"
|
||||||
|
" else\n"
|
||||||
|
" return nil, str\n"
|
||||||
|
" end\n"
|
||||||
|
" end\n"
|
||||||
|
"end\n"
|
||||||
|
"tio.alwaysecho = true\n"
|
||||||
|
"setmetatable(tio, tio)\n";
|
||||||
|
|
||||||
// lua: sleep(seconds)
|
static bool alwaysecho(lua_State *L)
|
||||||
static int sleep_(lua_State *L)
|
{
|
||||||
|
bool b;
|
||||||
|
|
||||||
|
lua_getglobal(L, "tio");
|
||||||
|
lua_getfield(L, -1, "alwaysecho");
|
||||||
|
b = lua_toboolean(L, -1);
|
||||||
|
lua_pop(L, 2);
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int api_echo(lua_State *L)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
const char *str = luaL_checklstring(L, 1, &len);
|
||||||
|
|
||||||
|
if (option.timestamp)
|
||||||
|
{
|
||||||
|
char *pTimeStampNow = timestamp_current_time();
|
||||||
|
if (pTimeStampNow)
|
||||||
|
{
|
||||||
|
tio_printf("%s", str);
|
||||||
|
if (option.log)
|
||||||
|
{
|
||||||
|
log_printf("\n[%s] %s", pTimeStampNow, str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (size_t i=0; i<len; i++)
|
||||||
|
{
|
||||||
|
putchar(str[i]);
|
||||||
|
|
||||||
|
if (option.log)
|
||||||
|
log_putc(str[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void maybe_echo(lua_State *L)
|
||||||
|
{
|
||||||
|
if (alwaysecho(L))
|
||||||
|
{
|
||||||
|
lua_pushcfunction(L, api_echo);
|
||||||
|
lua_pushvalue(L, -2);
|
||||||
|
lua_call(L, 1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lua: tio.sleep(seconds)
|
||||||
|
static int api_sleep(lua_State *L)
|
||||||
{
|
{
|
||||||
long seconds = lua_tointeger(L, 1);
|
long seconds = lua_tointeger(L, 1);
|
||||||
|
|
||||||
|
|
@ -77,8 +140,8 @@ static int sleep_(lua_State *L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// lua: msleep(miliseconds)
|
// lua: tio.msleep(miliseconds)
|
||||||
static int msleep(lua_State *L)
|
static int api_msleep(lua_State *L)
|
||||||
{
|
{
|
||||||
long mseconds = lua_tointeger(L, 1);
|
long mseconds = lua_tointeger(L, 1);
|
||||||
long useconds = mseconds * 1000;
|
long useconds = mseconds * 1000;
|
||||||
|
|
@ -94,7 +157,7 @@ static int msleep(lua_State *L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// lua: line_set(dtr,rts,cts,dsr,cd,ri)
|
// lua: tio.line_set(dtr,rts,cts,dsr,cd,ri)
|
||||||
static int line_set(lua_State *L)
|
static int line_set(lua_State *L)
|
||||||
{
|
{
|
||||||
tty_line_config_t line_config[6] = { };
|
tty_line_config_t line_config[6] = { };
|
||||||
|
|
@ -148,11 +211,11 @@ static int line_set(lua_State *L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// lua: modem_send(file, protocol)
|
// lua: tio.send(file, protocol)
|
||||||
static int modem_send(lua_State *L)
|
static int api_send(lua_State *L)
|
||||||
{
|
{
|
||||||
const char *file = lua_tostring(L, 1);
|
const char *file = luaL_checkstring(L, 1);
|
||||||
int protocol = lua_tointeger(L, 2);
|
int protocol = luaL_checkinteger(L, 2);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (file == NULL)
|
if (file == NULL)
|
||||||
|
|
@ -184,313 +247,118 @@ static int modem_send(lua_State *L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// lua: send(string)
|
// lua: tio.write(string)
|
||||||
static int write_(lua_State *L)
|
static int api_write(lua_State *L)
|
||||||
{
|
{
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
const char *string = lua_tolstring(L, 1, &len);
|
const char *string = luaL_checklstring(L, 1, &len);
|
||||||
|
ssize_t ret;
|
||||||
int ret;
|
int attempts = 100;
|
||||||
|
|
||||||
if (string == NULL)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
do {
|
||||||
ret = write(device_fd, string, len);
|
ret = write(device_fd, string, len);
|
||||||
|
if (ret < 0)
|
||||||
|
return luaL_error(L, "%s", strerror(errno));
|
||||||
|
|
||||||
|
len -= ret;
|
||||||
|
string += ret;
|
||||||
|
} while (len > 0 && --attempts);
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
return luaL_error(L, "partial write");
|
||||||
|
|
||||||
fsync(device_fd); // flush these characters now
|
fsync(device_fd); // flush these characters now
|
||||||
tcdrain(device_fd); //ensure we flushed characters to our device
|
tcdrain(device_fd); //ensure we flushed characters to our device
|
||||||
|
|
||||||
lua_pushnumber(L, ret);
|
lua_getglobal(L, "tio");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to add a character to the circular expect buffer
|
// lua: tio.read(size, timeout)
|
||||||
static void expect_buffer_add(char c)
|
static int api_read(lua_State *L)
|
||||||
{
|
{
|
||||||
if (!c)
|
int size = luaL_checkinteger(L, 1);
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer_size < MAX_BUFFER_SIZE)
|
|
||||||
{
|
|
||||||
circular_buffer[buffer_size++] = c;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Shift the buffer to accommodate the new character
|
|
||||||
memmove(circular_buffer, circular_buffer + 1, MAX_BUFFER_SIZE - 1);
|
|
||||||
circular_buffer[MAX_BUFFER_SIZE - 1] = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to match against the circular expect buffer using regex
|
|
||||||
static bool match_regex(regex_t *regex)
|
|
||||||
{
|
|
||||||
char buffer[MAX_BUFFER_SIZE + 1]; // Temporary buffer for regex matching
|
|
||||||
const char *s = circular_buffer;
|
|
||||||
regmatch_t pmatch[1];
|
|
||||||
regoff_t len;
|
|
||||||
|
|
||||||
memcpy(buffer, circular_buffer, buffer_size);
|
|
||||||
buffer[buffer_size] = '\0'; // Null-terminate the buffer
|
|
||||||
|
|
||||||
// Match against the regex
|
|
||||||
int ret = regexec(regex, buffer, 1, pmatch, 0);
|
|
||||||
if (!ret)
|
|
||||||
{
|
|
||||||
// Match found
|
|
||||||
len = pmatch[0].rm_eo - pmatch[0].rm_so;
|
|
||||||
memcpy(match_string, s + pmatch[0].rm_so, len);
|
|
||||||
match_string[len] = '\0';
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (ret == REG_NOMATCH)
|
|
||||||
{
|
|
||||||
// No match found, do nothing
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Error occurred during matching
|
|
||||||
tio_error_print("Regex match failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to echo a buffer to stdout and to the log
|
|
||||||
// per the option.timestamp and option.log settings
|
|
||||||
static void echo_buffer(char buffer[], ssize_t len)
|
|
||||||
{
|
|
||||||
if (option.timestamp)
|
|
||||||
{
|
|
||||||
char *pTimeStampNow;
|
|
||||||
pTimeStampNow = timestamp_current_time();
|
|
||||||
if (pTimeStampNow)
|
|
||||||
{
|
|
||||||
tio_printf("%s", buffer); //does timestamps for us
|
|
||||||
if (option.log)
|
|
||||||
{
|
|
||||||
log_printf("\n[%s] %s", pTimeStampNow, buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (ssize_t i=0; i<len; i++)
|
|
||||||
{
|
|
||||||
putchar(buffer[i]);
|
|
||||||
|
|
||||||
if (option.log)
|
|
||||||
{
|
|
||||||
log_putc(buffer[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// lua: ret,string = read(size, timeout)
|
|
||||||
static int read_string(lua_State *L)
|
|
||||||
{
|
|
||||||
int size = lua_tointeger(L, 1) + 1; //plus one for null-terminated string
|
|
||||||
int timeout = lua_tointeger(L, 2);
|
int timeout = lua_tointeger(L, 2);
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
char *buffer = calloc(1, size);
|
|
||||||
if (buffer == NULL)
|
|
||||||
{
|
|
||||||
ret = -1; // Error
|
|
||||||
goto error_rs;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeout == 0)
|
if (timeout == 0)
|
||||||
{
|
{
|
||||||
timeout = -1; // Wait forever
|
timeout = -1; // Wait forever
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t bytes_read = read_poll(device_fd, buffer, size, timeout);
|
luaL_Buffer buffer;
|
||||||
if (bytes_read < 0)
|
luaL_buffinit(L, &buffer);
|
||||||
|
|
||||||
|
#if LUA_VERSION_NUM >= 502
|
||||||
|
char *p = luaL_prepbuffsize(&buffer, size);
|
||||||
|
#else
|
||||||
|
if (size > LUAL_BUFFERSIZE)
|
||||||
|
return luaL_error(L, "buffer overflow, max size is: %d", LUAL_BUFFERSIZE);
|
||||||
|
char *p = luaL_prepbuffer(&buffer);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ssize_t ret = read_poll(device_fd, p, size, timeout);
|
||||||
|
if (ret < 0)
|
||||||
|
return luaL_error(L, "%s", strerror(errno));
|
||||||
|
|
||||||
|
luaL_addsize(&buffer, ret);
|
||||||
|
luaL_pushresult(&buffer);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
{
|
{
|
||||||
ret = -1; // Error
|
// On timeout return nil instead of an empty string
|
||||||
goto error_rs;
|
lua_pop(L, 1);
|
||||||
}
|
lua_pushnil(L);
|
||||||
else if (bytes_read == 0)
|
|
||||||
{
|
|
||||||
ret = 0; // Timeout
|
|
||||||
goto error_rs;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer[bytes_read] = (char)0;
|
maybe_echo(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
echo_buffer(&buffer[0], bytes_read);
|
return 1;
|
||||||
ret = bytes_read;
|
}
|
||||||
|
|
||||||
error_rs:
|
// lua: string = tio.readline(timeout)
|
||||||
lua_pushnumber(L, ret);
|
static int api_readline(lua_State *L) {
|
||||||
if (buffer != NULL)
|
int timeout = lua_tointeger(L, 1); //ms
|
||||||
|
luaL_Buffer b;
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
if (timeout == 0)
|
||||||
{
|
{
|
||||||
if (ret > 0) {
|
timeout = -1; // Wait forever
|
||||||
lua_pushlstring(L, buffer, ret);
|
|
||||||
} else {
|
|
||||||
lua_pushstring(L, "");
|
|
||||||
}
|
}
|
||||||
free(buffer);
|
|
||||||
}
|
luaL_buffinit(L, &b);
|
||||||
else
|
luaL_prepbuffer(&b);
|
||||||
|
while (true) {
|
||||||
|
int ret = read_poll(device_fd, &ch, 1, timeout);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return luaL_error(L, "%s", strerror(errno));
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
{
|
{
|
||||||
lua_pushstring(L, ""); // give empty string to caller
|
luaL_pushresult(&b);
|
||||||
}
|
maybe_echo(L);
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_insert(L, -2);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// lua: ret,string = read_line(timeout)
|
|
||||||
static int read_line(lua_State *L)
|
|
||||||
{
|
|
||||||
static char linebuf[READ_LINE_SIZE];
|
|
||||||
int timeout = lua_tointeger(L, 1); //ms
|
|
||||||
int ret = 0;
|
|
||||||
int read_result = 1; //enable reading input from device
|
|
||||||
char ch;
|
|
||||||
int bytes_read = 0;
|
|
||||||
|
|
||||||
linebuf[0] = '\0';
|
|
||||||
if (timeout == 0)
|
|
||||||
{
|
|
||||||
timeout = -1; // Wait forever
|
|
||||||
}
|
|
||||||
|
|
||||||
// loop reading input until a newline seen or timeout
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
read_result = read_poll(device_fd, &ch, 1, timeout);
|
|
||||||
if (read_result < 0)
|
|
||||||
{
|
|
||||||
ret = -1; // Error
|
|
||||||
linebuf[bytes_read] = '\0';
|
|
||||||
goto error_rl;
|
|
||||||
}
|
|
||||||
else if (!read_result)
|
|
||||||
{
|
|
||||||
// Timeout returns a non-empty linebuf as a 'line'
|
|
||||||
ret = bytes_read;
|
|
||||||
linebuf[bytes_read] = '\0';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else // we got a character, so handle it
|
|
||||||
{
|
|
||||||
if (ch == '\n')
|
if (ch == '\n')
|
||||||
{
|
{
|
||||||
linebuf[bytes_read] = '\0';
|
luaL_pushresult(&b);
|
||||||
break;
|
maybe_echo(L);
|
||||||
}
|
return 1;
|
||||||
else if (bytes_read <= (READ_LINE_SIZE-2))
|
|
||||||
{
|
|
||||||
if (isprint(ch)) // store all printable chars
|
|
||||||
{
|
|
||||||
linebuf[bytes_read++] = ch;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
luaL_addchar(&b, ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes_read)
|
// lua: table = tio.ttysearch()
|
||||||
{
|
static int api_ttysearch(lua_State *L)
|
||||||
echo_buffer(linebuf, bytes_read);
|
|
||||||
}
|
|
||||||
ret = bytes_read;
|
|
||||||
|
|
||||||
error_rl:
|
|
||||||
lua_pushnumber(L, ret);
|
|
||||||
lua_pushlstring(L, linebuf, ret);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// lua: expect(string, timeout)
|
|
||||||
static int expect(lua_State *L)
|
|
||||||
{
|
|
||||||
const char *string = lua_tostring(L, 1);
|
|
||||||
long timeout = lua_tointeger(L, 2);
|
|
||||||
regex_t regex;
|
|
||||||
int ret = 0;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
// Resets buffer to ignore previous `expect` calls
|
|
||||||
buffer_size = 0;
|
|
||||||
match_string[0] = '\0';
|
|
||||||
|
|
||||||
if ((string == NULL) || (timeout < 0))
|
|
||||||
{
|
|
||||||
ret = -1;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeout == 0)
|
|
||||||
{
|
|
||||||
// Let poll() wait forever
|
|
||||||
timeout = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compile the regular expression
|
|
||||||
ret = regcomp(®ex, string, REG_EXTENDED);
|
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
tio_error_print("Could not compile regex");
|
|
||||||
ret = -1;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Main loop to read and match
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
ssize_t bytes_read = read_poll(device_fd, &c, 1, timeout);
|
|
||||||
if (bytes_read > 0)
|
|
||||||
{
|
|
||||||
putchar(c);
|
|
||||||
expect_buffer_add(c);
|
|
||||||
|
|
||||||
if (option.log)
|
|
||||||
{
|
|
||||||
log_putc(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match against the entire buffer
|
|
||||||
if (match_regex(®ex))
|
|
||||||
{
|
|
||||||
ret = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Timeout or error
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
regfree(®ex);
|
|
||||||
|
|
||||||
error:
|
|
||||||
lua_pushnumber(L, ret);
|
|
||||||
lua_pushstring(L, match_string);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// lua: exit(code)
|
|
||||||
static int exit_(lua_State *L)
|
|
||||||
{
|
|
||||||
long code = lua_tointeger(L, 1);
|
|
||||||
|
|
||||||
exit(code);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// lua: list = tty_search()
|
|
||||||
static int tty_search_(lua_State *L)
|
|
||||||
{
|
{
|
||||||
UNUSED(L);
|
UNUSED(L);
|
||||||
GList *iter;
|
GList *iter;
|
||||||
|
|
@ -556,66 +424,7 @@ static void script_buffer_run(lua_State *L, const char *script_buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct luaL_Reg tio_lib[] =
|
static void script_file_run(lua_State *L, const char *filename)
|
||||||
{
|
|
||||||
{ "sleep", sleep_},
|
|
||||||
{ "msleep", msleep},
|
|
||||||
{ "line_set", line_set},
|
|
||||||
{ "send", modem_send},
|
|
||||||
{ "write", write_},
|
|
||||||
{ "read", read_string},
|
|
||||||
{ "read_line", read_line},
|
|
||||||
{ "expect", expect},
|
|
||||||
{ "exit", exit_},
|
|
||||||
{ "tty_search", tty_search_},
|
|
||||||
{NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
#if !defined LUA_VERSION_NUM || LUA_VERSION_NUM==501
|
|
||||||
/*
|
|
||||||
** Adapted from Lua 5.2.0 (for backwards compatibility)
|
|
||||||
*/
|
|
||||||
static void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup)
|
|
||||||
{
|
|
||||||
luaL_checkstack(L, nup+1, "too many upvalues");
|
|
||||||
for (; l->name != NULL; l++) { /* fill the table with given functions */
|
|
||||||
int i;
|
|
||||||
lua_pushstring(L, l->name);
|
|
||||||
for (i = 0; i < nup; i++) /* copy upvalues to the top */
|
|
||||||
lua_pushvalue(L, -(nup+1));
|
|
||||||
lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */
|
|
||||||
lua_settable(L, -(nup + 3));
|
|
||||||
}
|
|
||||||
lua_pop(L, nup); /* remove upvalues */
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void script_load(lua_State *L)
|
|
||||||
{
|
|
||||||
int error;
|
|
||||||
|
|
||||||
error = luaL_loadbuffer(L, script_init, strlen(script_init), "tio") || lua_pcall(L, 0, 0, 0);
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
tio_error_print("%s\n", lua_tostring(L, -1));
|
|
||||||
lua_pop(L, 1); // Pop error message from the stack
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int lua_register_tio(lua_State *L)
|
|
||||||
{
|
|
||||||
// Register lxi functions
|
|
||||||
lua_getglobal(L, "_G");
|
|
||||||
luaL_setfuncs(L, tio_lib, 0);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
|
|
||||||
// Load lua init script
|
|
||||||
script_load(L);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void script_file_run(lua_State *L, const char *filename)
|
|
||||||
{
|
{
|
||||||
if (strlen(filename) == 0)
|
if (strlen(filename) == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -631,13 +440,39 @@ void script_file_run(lua_State *L, const char *filename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void script_set_global(lua_State *L, const char *name, long value)
|
static const struct luaL_Reg tio_lib[] =
|
||||||
|
{
|
||||||
|
{ "echo", api_echo},
|
||||||
|
{ "sleep", api_sleep},
|
||||||
|
{ "msleep", api_msleep},
|
||||||
|
{ "line_set", line_set},
|
||||||
|
{ "send", api_send},
|
||||||
|
{ "write", api_write},
|
||||||
|
{ "read", api_read},
|
||||||
|
{ "readline", api_readline},
|
||||||
|
{ "ttysearch", api_ttysearch},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void script_load(lua_State *L)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = luaL_loadbuffer(L, script_init, strlen(script_init), "tio") || lua_pcall(L, 0, 0, 0);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
tio_error_print("%s\n", lua_tostring(L, -1));
|
||||||
|
lua_pop(L, 1); // Pop error message from the stack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void script_set_global(lua_State *L, const char *name, long value)
|
||||||
{
|
{
|
||||||
lua_pushnumber(L, value);
|
lua_pushnumber(L, value);
|
||||||
lua_setglobal(L, name);
|
lua_setglobal(L, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void script_set_globals(lua_State *L)
|
static void script_set_globals(lua_State *L)
|
||||||
{
|
{
|
||||||
script_set_global(L, "toggle", 2);
|
script_set_global(L, "toggle", 2);
|
||||||
script_set_global(L, "high", 1);
|
script_set_global(L, "high", 1);
|
||||||
|
|
@ -647,6 +482,14 @@ void script_set_globals(lua_State *L)
|
||||||
script_set_global(L, "YMODEM", YMODEM);
|
script_set_global(L, "YMODEM", YMODEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LUA_VERSION_NUM >= 502
|
||||||
|
static int luaopen_tio(lua_State *L)
|
||||||
|
{
|
||||||
|
luaL_newlib(L, tio_lib);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void script_run(int fd, const char *script_filename)
|
void script_run(int fd, const char *script_filename)
|
||||||
{
|
{
|
||||||
lua_State *L;
|
lua_State *L;
|
||||||
|
|
@ -656,8 +499,15 @@ void script_run(int fd, const char *script_filename)
|
||||||
L = luaL_newstate();
|
L = luaL_newstate();
|
||||||
luaL_openlibs(L);
|
luaL_openlibs(L);
|
||||||
|
|
||||||
// Bind tio functions
|
#if LUA_VERSION_NUM >= 502
|
||||||
lua_register_tio(L);
|
luaL_requiref(L, "tio", luaopen_tio, 1);
|
||||||
|
#else
|
||||||
|
luaL_register(L, "tio", tio_lib);
|
||||||
|
#endif
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
// Load lua init script
|
||||||
|
script_load(L);
|
||||||
|
|
||||||
// Initialize globals
|
// Initialize globals
|
||||||
script_set_globals(L);
|
script_set_globals(L);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue