Add some subcommand-equivalent functions to the Lua API

Add following functions to Lua API

tio.send_break()
tio.set_local_echo()
tio.set_log()
tio.flush_data_io_buffer()
tio.set_input_mode()
tio.set_output_mode()
tio.set_raw_mode()
tio.set_raw_mode_interactive()
tio.set_timestamp_mode()
tio.set_exec_shell_command()
tio.get_version()
This commit is contained in:
yabu76 2026-02-13 07:36:55 +09:00
parent d28b5f4452
commit 2069e77123

View file

@ -40,6 +40,7 @@
#include "fs.h"
#include "timestamp.h"
#include "termios.h"
#include "version.h"
#define MAX_BUFFER_SIZE 2000 // Maximum size of circular buffer
#define READ_LINE_SIZE 4096 // read_line buffer length
@ -49,6 +50,14 @@ static lua_State *script_interp = NULL;
// clang-format off
static char script_init[] =
"tio.C = {\n"
" EXPECT_CLEANUP_READ_SIZE = 4096,\n"
" WAIT_FOREVER = 0,\n"
" NOWAIT = -1,\n"
"}\n"
"tio.clear_screen = function()\n"
" io.write('\\x1bc')\n"
"end\n"
"tio.set = function(arg)\n"
" local dtr = arg.DTR or -1\n"
" local rts = arg.RTS or -1\n"
@ -58,10 +67,6 @@ static char script_init[] =
" local ri = arg.RI or -1\n"
" tio.line_set(dtr, rts, cts, dsr, cd, ri)\n"
"end\n"
"tio.C = {}\n"
"tio.C.EXPECT_CLEANUP_READ_SIZE = 4096\n"
"tio.C.WAIT_FOREVER = 0\n"
"tio.C.NOWAIT = -1\n"
"tio.expect = function(pattern, timeout)\n"
" local str = ''\n"
" while true do\n"
@ -519,6 +524,207 @@ static int api_ttysearch(lua_State *L)
return 1;
}
// lua: tio.send_break()
static int api_send_break(lua_State *L)
{
if (device_fd == 0)
{
return luaL_error(L, "tty device not ready");
}
tcsendbreak(device_fd, 0);
return 0;
}
// lua: tio.set_local_echo(boolean local_echo)
static int api_set_local_echo(lua_State *L)
{
int arg_num = lua_gettop(L);
if (arg_num == 0)
{
option.local_echo = true;
return 0;
}
if ( ! (lua_isboolean(L, 1) || lua_isnil(L, 1)) )
{
return luaL_error(L, "argument is not boolean");
}
option.local_echo = lua_toboolean(L, 1);
return 0;
}
// lua: tio.set_log(boolean log)
static int api_set_log(lua_State *L)
{
int arg_num = lua_gettop(L);
if (arg_num == 0)
{
option.log = true;
}
else /* arg_num > 0 */
{
if ( ! (lua_isboolean(L, 1) || lua_isnil(L, 1)) )
{
return luaL_error(L, "argument is not boolean");
}
option.log = lua_toboolean(L, 1);
}
if (option.log)
{
if (log_open(option.log_filename) != 0)
{
option.log = false;
return luaL_error(L, "cant open log file");
}
}
else
{
log_close();
}
return 0;
}
// lua: tio.flush_data_io_buffer()
static int api_flush_data_io_buffer(lua_State *L)
{
if (device_fd == 0)
{
return luaL_error(L, "tty device not ready");
}
tcflush(device_fd, TCIOFLUSH);
return 0;
}
// lua: tio.set_input_mode(tio.C.IM_NORMAL | tio.C.IM_HEX | tio.C.IM_LINE)
static int api_set_input_mode(lua_State *L)
{
int input_mode = luaL_optinteger(L, 1, INPUT_MODE_NORMAL);
switch (input_mode)
{
case INPUT_MODE_NORMAL:
case INPUT_MODE_HEX:
case INPUT_MODE_LINE:
break;
default:
return luaL_error(L, "invalid input mode");
}
option.input_mode = input_mode;
return 0;
}
// lua: tio.set_output_mode(tio.C.OM_NORMAL | tio.C.OM_HEX)
static int api_set_output_mode(lua_State *L)
{
int output_mode = luaL_optinteger(L, 1, OUTPUT_MODE_NORMAL);
switch (output_mode)
{
case OUTPUT_MODE_NORMAL:
case OUTPUT_MODE_HEX:
break;
default:
return luaL_error(L, "invalid output mode");
}
option.output_mode = output_mode;
return 0;
}
// lua: tio.set_raw_mode(tio.C.RAW_OFF | tio.C.RAW_ON | tio.C.RAW_ON_NODELAY)
static int api_set_raw_mode(lua_State *L)
{
int raw_mode = luaL_optinteger(L, 1, RAW_ON_DELAY);
switch (raw_mode)
{
case RAW_OFF:
case RAW_ON_DELAY:
case RAW_ON_NODELAY:
break;
default:
return luaL_error(L, "invalid raw mode");
}
option.raw = raw_mode;
if (state != STATE_INTERACTIVE)
{
tty_tcsetattr(device_fd);
}
return 0;
}
// lua: tio.set_raw_mode_interactive(tio.C.RAW_OFF | tio.C.RAW_ON | tio.C.RAW_ON_NODELAY)
static int api_set_raw_mode_interactive(lua_State *L)
{
int raw_mode = luaL_optinteger(L, 1, RAW_ON_DELAY);
switch (raw_mode)
{
case RAW_OFF:
case RAW_ON_DELAY:
case RAW_ON_NODELAY:
break;
default:
return luaL_error(L, "invalid raw mode");
}
option.raw_interactive = raw_mode;
if (state == STATE_INTERACTIVE)
{
tty_tcsetattr(device_fd);
}
return 0;
}
// lua: tio.set_timestamp_mode(tio.C.TS_NONE | tio.C.TS_24HOUR | ...)
static int api_set_timestamp_mode(lua_State *L)
{
int timestamp_mode = luaL_optinteger(L, 1, TIMESTAMP_24HOUR);
switch (timestamp_mode)
{
case TIMESTAMP_NONE:
case TIMESTAMP_24HOUR:
case TIMESTAMP_24HOUR_START:
case TIMESTAMP_24HOUR_DELTA:
case TIMESTAMP_ISO8601:
case TIMESTAMP_EPOCH:
case TIMESTAMP_EPOCH_USEC:
break;
default:
return luaL_error(L, "invalid timestamp mode");
}
option.timestamp = timestamp_mode;
return 0;
}
// lua: tio.exec_shell_command(string:command)
int api_exec_shell_command(lua_State *L)
{
const char *command = luaL_checkstring(L, 1);
if (command == NULL)
{
return luaL_error(L, "no command");
}
if (device_fd == 0)
{
return luaL_error(L, "tty device not ready");
}
int result;
state_t state_orig = state;
state = STATE_EXEC_SHELL_COMMAND;
tty_tcsetattr(device_fd);
result = execute_shell_command(device_fd, command);
state = state_orig;
tty_tcsetattr(device_fd);
if (result < 0)
{
return luaL_error(L, "command failed.");
}
return 0;
}
// lua: tio.get_version()
static int api_get_version(lua_State *L)
{
lua_pushstring(L, VERSION);
return 1;
}
static void script_buffer_run(lua_State *L, const char *script_buffer)
{
int error;
@ -561,6 +767,19 @@ static const struct luaL_Reg tio_lib[] =
{ "read", api_read},
{ "readline", api_readline},
{ "ttysearch", api_ttysearch},
{ "send_break", api_send_break},
{ "set_local_echo", api_set_local_echo},
{ "set_log", api_set_log},
{ "flush_data_io_buffer", api_flush_data_io_buffer},
{ "set_input_mode", api_set_input_mode},
{ "set_output_mode", api_set_output_mode},
{ "set_raw_mode", api_set_raw_mode},
{ "set_raw_mode_interactive", api_set_raw_mode_interactive},
{ "set_timestamp_mode", api_set_timestamp_mode},
{ "exec_shell_command", api_exec_shell_command},
{ "get_version", api_get_version},
{NULL, NULL}
};
// clang-format on
@ -577,23 +796,61 @@ static void script_load(lua_State *L)
}
}
static void script_set_global(lua_State *L, const char *name, long value)
static void script_set_global_integer(lua_State *L, const char *name, int value)
{
lua_pushnumber(L, value);
lua_pushinteger(L, value);
lua_setglobal(L, name);
}
static void script_set_globals(lua_State *L)
{
script_set_global(L, "toggle", 2);
script_set_global(L, "high", 1);
script_set_global(L, "low", 0);
script_set_global(L, "XMODEM_SUM", XMODEM_SUM);
script_set_global(L, "XMODEM_CRC", XMODEM_CRC);
script_set_global(L, "XMODEM_1K", XMODEM_1K);
script_set_global(L, "YMODEM", YMODEM);
script_set_global_integer(L, "toggle", 2);
script_set_global_integer(L, "high", 1);
script_set_global_integer(L, "low", 0);
script_set_global_integer(L, "XMODEM_SUM", XMODEM_SUM);
script_set_global_integer(L, "XMODEM_CRC", XMODEM_CRC);
script_set_global_integer(L, "XMODEM_1K", XMODEM_1K);
script_set_global_integer(L, "YMODEM", YMODEM);
}
static void script_set_field_integer(lua_State *L, const char *name, int value)
{
lua_pushinteger(L, value);
lua_setfield(L, -2, name);
}
static void script_set_consts(lua_State *L)
{
lua_getglobal(L, "tio");
lua_getfield(L, -1, "C");
script_set_field_integer(L, "IM_NORMAL", INPUT_MODE_NORMAL);
script_set_field_integer(L, "IM_HEX", INPUT_MODE_HEX);
script_set_field_integer(L, "IM_LINE", INPUT_MODE_LINE);
script_set_field_integer(L, "OM_NORMAL", OUTPUT_MODE_NORMAL);
script_set_field_integer(L, "OM_HEX", OUTPUT_MODE_HEX);
script_set_field_integer(L, "RAW_OFF", RAW_OFF);
script_set_field_integer(L, "RAW_ON", RAW_ON_DELAY);
script_set_field_integer(L, "RAW_ON_NODELAY", RAW_ON_NODELAY);
script_set_field_integer(L, "TS_OFF", TIMESTAMP_NONE);
script_set_field_integer(L, "TS_24HOUR", TIMESTAMP_24HOUR);
script_set_field_integer(L, "TS_24HOUR_START", TIMESTAMP_24HOUR_START);
script_set_field_integer(L, "TS_24HOUR_DELTA", TIMESTAMP_24HOUR_DELTA);
script_set_field_integer(L, "TS_ISO8601", TIMESTAMP_ISO8601);
script_set_field_integer(L, "TS_EPOCH", TIMESTAMP_EPOCH);
script_set_field_integer(L, "TS_EPOCH_USEC", TIMESTAMP_EPOCH_USEC);
script_set_field_integer(L, "LN_TOGGLE", 2);
script_set_field_integer(L, "LN_HIGH", 1);
script_set_field_integer(L, "LN_LOW", 0);
script_set_field_integer(L, "XM_SUM", XMODEM_SUM);
script_set_field_integer(L, "XM_CRC", XMODEM_CRC);
script_set_field_integer(L, "XM_1K", XMODEM_1K);
script_set_field_integer(L, "YM_NORMAL", YMODEM);
lua_pop(L, 2);
}
#if LUA_VERSION_NUM >= 502
static int luaopen_tio(lua_State *L)
{
@ -635,6 +892,7 @@ static lua_State *script_interp_new(void)
// Initialize globals
script_set_globals(L);
script_set_consts(L);
// Execute script-init file
if (option.script_init_filename) {