You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
695 lines
17 KiB
695 lines
17 KiB
|
3 days ago
|
#include "lua_base.h"
|
||
|
|
|
||
|
|
static char *history_buffer[MAX_HISTORY_LINES]; // 指针数组
|
||
|
|
static int history_count = 0; // 当前存储了多少条
|
||
|
|
static int history_index = -1; // 当前正在浏览的历史索引 (-1 表示当前输入)
|
||
|
|
lua_output lua_print = NULL;
|
||
|
|
|
||
|
|
static lua_State *L = NULL;
|
||
|
|
static char *buffer = NULL;
|
||
|
|
static char *wrapped_code = NULL;
|
||
|
|
static size_t buffer_len = 0;
|
||
|
|
static int incomplete = 0;
|
||
|
|
|
||
|
|
static size_t capacity = 256;
|
||
|
|
static char *linebuffer = NULL;
|
||
|
|
static size_t len = 0;
|
||
|
|
static size_t cursor_pos = 0;
|
||
|
|
static int escape_mode = 0; // 0: 正常, 1: 收到 ESC, 2: 收到 ESC [
|
||
|
|
|
||
|
|
static void add_to_history(const char *cmd)
|
||
|
|
{
|
||
|
|
if (cmd == NULL || strlen(cmd) == 0) return;
|
||
|
|
|
||
|
|
history_index = -1;
|
||
|
|
|
||
|
|
if (history_count > 0 && strcmp(history_buffer[history_count - 1], cmd) == 0)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (history_count >= MAX_HISTORY_LINES)
|
||
|
|
{
|
||
|
|
RD_FREE(history_buffer[0]);
|
||
|
|
for (int i = 0; i < MAX_HISTORY_LINES - 1; i++)
|
||
|
|
{
|
||
|
|
history_buffer[i] = history_buffer[i + 1];
|
||
|
|
}
|
||
|
|
history_count = MAX_HISTORY_LINES - 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
char *new_entry = (char *)RD_MALLOC(strlen(cmd) + 1);
|
||
|
|
if (new_entry)
|
||
|
|
{
|
||
|
|
strcpy(new_entry, cmd);
|
||
|
|
history_buffer[history_count++] = new_entry;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static const char* get_history(int offset)
|
||
|
|
{
|
||
|
|
if (history_count == 0) return NULL;
|
||
|
|
|
||
|
|
if (offset < 0)
|
||
|
|
{
|
||
|
|
if (history_index == -1)
|
||
|
|
{
|
||
|
|
history_index = history_count - 1;
|
||
|
|
}
|
||
|
|
else if (history_index > 0)
|
||
|
|
{
|
||
|
|
history_index--;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (history_index != -1)
|
||
|
|
{
|
||
|
|
history_index++;
|
||
|
|
if (history_index >= history_count)
|
||
|
|
{
|
||
|
|
history_index = -1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (history_index == -1) return NULL;
|
||
|
|
|
||
|
|
return history_buffer[history_index];
|
||
|
|
}
|
||
|
|
|
||
|
|
static char *trim(char *str)
|
||
|
|
{
|
||
|
|
while (isspace((unsigned char)*str)) str++;
|
||
|
|
if (*str == 0) return str;
|
||
|
|
char *end = str + strlen(str) - 1;
|
||
|
|
while (end > str && isspace((unsigned char)*end)) end--;
|
||
|
|
end[1] = '\0';
|
||
|
|
return str;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void print_number_fixed3(double num)
|
||
|
|
{
|
||
|
|
if (NULL == lua_print) return;
|
||
|
|
|
||
|
|
if (num < 0) {
|
||
|
|
lua_print("-");
|
||
|
|
num = -num;
|
||
|
|
}
|
||
|
|
|
||
|
|
lua_Integer int_part = (lua_Integer)num;
|
||
|
|
|
||
|
|
double frac_double = (num - (double)int_part) * 1000.0 + 0.5;
|
||
|
|
|
||
|
|
int frac_part = (int)frac_double;
|
||
|
|
|
||
|
|
if (frac_part >= 1000) {
|
||
|
|
int_part += 1;
|
||
|
|
frac_part -= 1000;
|
||
|
|
}
|
||
|
|
|
||
|
|
lua_print("%ld", (long)int_part);
|
||
|
|
|
||
|
|
if (frac_part > 0) {
|
||
|
|
lua_print(".");
|
||
|
|
|
||
|
|
char frac_buf[4];
|
||
|
|
frac_buf[0] = (frac_part / 100) + '0';
|
||
|
|
frac_buf[1] = (frac_part % 100 / 10) + '0';
|
||
|
|
frac_buf[2] = (frac_part % 10) + '0';
|
||
|
|
frac_buf[3] = '\0';
|
||
|
|
|
||
|
|
int end_idx = 2;
|
||
|
|
while (end_idx >= 0 && frac_buf[end_idx] == '0') {
|
||
|
|
end_idx--;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i <= end_idx; i++) {
|
||
|
|
lua_print("%c", frac_buf[i]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void print_result(lua_State *L, int status)
|
||
|
|
{
|
||
|
|
if (NULL == lua_print) return;
|
||
|
|
|
||
|
|
if (status != LUA_OK)
|
||
|
|
{
|
||
|
|
lua_print("Error: %s\n", lua_tostring(L, -1));
|
||
|
|
lua_pop(L, 1);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
int n = lua_gettop(L);
|
||
|
|
if (n == 0) return; // 没有返回值
|
||
|
|
|
||
|
|
// 打印所有返回值
|
||
|
|
for (int i = 1; i <= n; i++)
|
||
|
|
{
|
||
|
|
if (i > 1)
|
||
|
|
{
|
||
|
|
lua_print("\t"); // 多个值之间用制表符分隔
|
||
|
|
}
|
||
|
|
|
||
|
|
if (lua_isnumber(L, i))
|
||
|
|
{
|
||
|
|
// 优化数字显示:如果是整数则不显示小数点
|
||
|
|
double num = lua_tonumber(L, i);
|
||
|
|
if (num == (lua_Integer)num)
|
||
|
|
{
|
||
|
|
lua_print("%d", (lua_Integer)num);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
print_number_fixed3(num);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (lua_isstring(L, i))
|
||
|
|
{
|
||
|
|
lua_print("%s", lua_tostring(L, i));
|
||
|
|
}
|
||
|
|
else if (lua_isboolean(L, i))
|
||
|
|
{
|
||
|
|
lua_print("%s", lua_toboolean(L, i) ? "true" : "false");
|
||
|
|
}
|
||
|
|
else if (lua_isnil(L, i))
|
||
|
|
{
|
||
|
|
lua_print("nil");
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
lua_print("%s: %p", luaL_typename(L, i), lua_topointer(L, i));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
lua_print("\n");
|
||
|
|
lua_pop(L, n);
|
||
|
|
}
|
||
|
|
|
||
|
|
static char *readline(const char *_pcPrompt, char *_pcBuffer, int _iSize, int _iEcho)
|
||
|
|
{
|
||
|
|
if (NULL == lua_print)
|
||
|
|
{
|
||
|
|
log_e("\nError: printf is NULL\n");
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (linebuffer == NULL)
|
||
|
|
{
|
||
|
|
linebuffer = (char *)RD_MALLOC(capacity);
|
||
|
|
if (!linebuffer)
|
||
|
|
{
|
||
|
|
log_e("\nError: Out of memory\n");
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t limit = (_iSize < 0) ? SIZE_MAX : (size_t)_iSize;
|
||
|
|
|
||
|
|
for (size_t i = 0; i < limit; i++)
|
||
|
|
{
|
||
|
|
int c;
|
||
|
|
if (NULL == _pcBuffer)
|
||
|
|
{
|
||
|
|
c = fgetc(stdin);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
c = (int)_pcBuffer[i];
|
||
|
|
}
|
||
|
|
|
||
|
|
if (c == EOF)
|
||
|
|
{
|
||
|
|
lua_print("\n");
|
||
|
|
RD_FREE(linebuffer);
|
||
|
|
linebuffer = NULL;
|
||
|
|
log_e("\nError: End of EOF\n");
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (len == 0 && cursor_pos == 0 && (c == '\n' || c == '\r'))
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (escape_mode == 1)
|
||
|
|
{
|
||
|
|
if (c == '[')
|
||
|
|
{
|
||
|
|
escape_mode = 2;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
escape_mode = 0;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (escape_mode == 2)
|
||
|
|
{
|
||
|
|
escape_mode = 0; // 先重置,无论是否匹配
|
||
|
|
|
||
|
|
if (c == 'A' || c == 'B')
|
||
|
|
{
|
||
|
|
const char *hist = (c == 'A') ? get_history(-1) : get_history(1);
|
||
|
|
|
||
|
|
lua_print("\r\033[K%s%s", _pcPrompt, hist ? hist : "");
|
||
|
|
|
||
|
|
if (hist)
|
||
|
|
{
|
||
|
|
len = strlen(hist);
|
||
|
|
if (len >= capacity - 1)
|
||
|
|
{
|
||
|
|
capacity = len + 10;
|
||
|
|
linebuffer = (char *)RD_REALLOC(linebuffer, capacity);
|
||
|
|
if(!linebuffer) return NULL;
|
||
|
|
}
|
||
|
|
strcpy(linebuffer, hist);
|
||
|
|
cursor_pos = len;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
len = 0;
|
||
|
|
cursor_pos = 0;
|
||
|
|
linebuffer[0] = '\0';
|
||
|
|
}
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
else if (c == 'C')
|
||
|
|
{
|
||
|
|
if (cursor_pos < len)
|
||
|
|
{
|
||
|
|
lua_print("%c", linebuffer[cursor_pos]);
|
||
|
|
cursor_pos++;
|
||
|
|
}
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
else if (c == 'D')
|
||
|
|
{
|
||
|
|
if (cursor_pos > 0)
|
||
|
|
{
|
||
|
|
lua_print("\b");
|
||
|
|
cursor_pos--;
|
||
|
|
}
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (c == 0x1B)
|
||
|
|
{
|
||
|
|
escape_mode = 1;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (c == '\n' || c == '\r')
|
||
|
|
{
|
||
|
|
if (_iEcho)
|
||
|
|
{
|
||
|
|
lua_print("\n");
|
||
|
|
}
|
||
|
|
linebuffer[len] = '\0';
|
||
|
|
|
||
|
|
char *result = strdup(linebuffer);
|
||
|
|
|
||
|
|
if (len > 0 && strcmp(linebuffer, "exit") != 0)
|
||
|
|
{
|
||
|
|
add_to_history(linebuffer);
|
||
|
|
}
|
||
|
|
|
||
|
|
len = 0;
|
||
|
|
cursor_pos = 0;
|
||
|
|
escape_mode = 0;
|
||
|
|
linebuffer[0] = '\0';
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (c == '\b' || c == 127)
|
||
|
|
{
|
||
|
|
if (cursor_pos > 0)
|
||
|
|
{
|
||
|
|
cursor_pos--;
|
||
|
|
for (size_t i = cursor_pos; i < len - 1; i++)
|
||
|
|
{
|
||
|
|
linebuffer[i] = linebuffer[i+1];
|
||
|
|
}
|
||
|
|
len--;
|
||
|
|
linebuffer[len] = '\0';
|
||
|
|
|
||
|
|
lua_print("\b");
|
||
|
|
for (size_t i = cursor_pos; i < len; i++)
|
||
|
|
{
|
||
|
|
lua_print("%c", linebuffer[i]);
|
||
|
|
}
|
||
|
|
lua_print(" ");
|
||
|
|
|
||
|
|
for (size_t i = cursor_pos; i <= len; i++)
|
||
|
|
{
|
||
|
|
lua_print("\b");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (c >= 32 && c <= 126)
|
||
|
|
{
|
||
|
|
if (len >= capacity - 1)
|
||
|
|
{
|
||
|
|
capacity += 256;
|
||
|
|
char *new_buf = (char *)RD_REALLOC(linebuffer, capacity);
|
||
|
|
if (!new_buf)
|
||
|
|
{
|
||
|
|
log_e("\nError: Out of memory\n");
|
||
|
|
RD_FREE(linebuffer);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
linebuffer = new_buf;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (size_t i = len; i > cursor_pos; i--)
|
||
|
|
{
|
||
|
|
linebuffer[i] = linebuffer[i-1];
|
||
|
|
}
|
||
|
|
|
||
|
|
linebuffer[cursor_pos] = (char)c;
|
||
|
|
len++;
|
||
|
|
linebuffer[len] = '\0';
|
||
|
|
if (_iEcho)
|
||
|
|
{
|
||
|
|
for (size_t i = cursor_pos; i < len; i++)
|
||
|
|
{
|
||
|
|
lua_print("%c", linebuffer[i]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
for (size_t i = cursor_pos; i < len - 1; i++)
|
||
|
|
{
|
||
|
|
lua_print("\b");
|
||
|
|
}
|
||
|
|
|
||
|
|
cursor_pos++;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
WEAK int luaopen_stm32(lua_State *L)
|
||
|
|
{
|
||
|
|
lua_newtable(L);
|
||
|
|
lua_setglobal(L, "st");
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
int lua_init(lua_output _lua_print)
|
||
|
|
{
|
||
|
|
if (NULL == _lua_print) return -1;
|
||
|
|
lua_print = _lua_print;
|
||
|
|
|
||
|
|
buffer_len = 0;
|
||
|
|
capacity = 256;
|
||
|
|
len = 0;
|
||
|
|
cursor_pos = 0;
|
||
|
|
incomplete = 0;
|
||
|
|
escape_mode = 0;
|
||
|
|
|
||
|
|
if (linebuffer != NULL)
|
||
|
|
{
|
||
|
|
RD_FREE(linebuffer);
|
||
|
|
linebuffer = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (buffer != NULL)
|
||
|
|
{
|
||
|
|
RD_FREE(buffer);
|
||
|
|
buffer = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (wrapped_code != NULL)
|
||
|
|
{
|
||
|
|
RD_FREE(wrapped_code);
|
||
|
|
wrapped_code = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (L != NULL)
|
||
|
|
{
|
||
|
|
lua_close(L);
|
||
|
|
L = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
L = luaL_newstate();
|
||
|
|
if (!L)
|
||
|
|
{
|
||
|
|
lua_print("Failed to create Lua state\n");
|
||
|
|
return RD_FAILURE;
|
||
|
|
}
|
||
|
|
luaL_openlibs(L);
|
||
|
|
|
||
|
|
luaopen_stm32(L);
|
||
|
|
|
||
|
|
lua_print("Lua REPL V5.4\nType 'exit' or Ctrl+D to quit.\n\n");
|
||
|
|
lua_print("%s", incomplete ? CONT_PROMPT : PROMPT);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int lua_repl(char *_pcBuffer, int _iSize, int _iEcho)
|
||
|
|
{
|
||
|
|
int iRet = 0;
|
||
|
|
|
||
|
|
char *line = readline(incomplete ? CONT_PROMPT : PROMPT, _pcBuffer, _iSize, _iEcho);
|
||
|
|
if (!line)
|
||
|
|
{
|
||
|
|
return RD_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (strcmp(line, "exit") == 0)
|
||
|
|
{
|
||
|
|
RD_FREE(line);
|
||
|
|
iRet = RD_SUCCESS;
|
||
|
|
goto cleanup;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (incomplete)
|
||
|
|
{
|
||
|
|
size_t line_len = strlen(line);
|
||
|
|
char *new_buf = RD_REALLOC(buffer, buffer_len + line_len + 2);
|
||
|
|
buffer = new_buf;
|
||
|
|
strcat(buffer, "\n");
|
||
|
|
strcat(buffer, line);
|
||
|
|
buffer_len += line_len + 1;
|
||
|
|
RD_FREE(line);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
RD_FREE(buffer);
|
||
|
|
buffer = line;
|
||
|
|
buffer_len = strlen(line);
|
||
|
|
}
|
||
|
|
|
||
|
|
char *final_code = NULL;
|
||
|
|
int status = LUA_ERRSYNTAX;
|
||
|
|
|
||
|
|
// 1. 预检查:是否明显是表达式?(数字、符号开头)
|
||
|
|
int try_return_first = 0;
|
||
|
|
const char *trimmed = trim(buffer);
|
||
|
|
int looks_like_block = (strncmp(trimmed, "function", 8) == 0) ||
|
||
|
|
(strncmp(trimmed, "if", 2) == 0) ||
|
||
|
|
(strncmp(trimmed, "for", 3) == 0) ||
|
||
|
|
(strncmp(trimmed, "while", 5) == 0) ||
|
||
|
|
(strncmp(trimmed, "do", 2) == 0) ||
|
||
|
|
(strncmp(trimmed, "repeat", 6) == 0);
|
||
|
|
if (strlen(trimmed) > 0)
|
||
|
|
{
|
||
|
|
char first = trimmed[0];
|
||
|
|
if (isdigit(first) || first == '(' || first == '"' || first == '\'' ||
|
||
|
|
first == '-' || first == '{' || first == '[')
|
||
|
|
{
|
||
|
|
try_return_first = 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 情况 A: 明显是表达式,直接加 return 编译
|
||
|
|
if (try_return_first)
|
||
|
|
{
|
||
|
|
wrapped_code = RD_MALLOC(buffer_len + 10);
|
||
|
|
sprintf(wrapped_code, "return %s", buffer);
|
||
|
|
final_code = wrapped_code;
|
||
|
|
status = luaL_loadbuffer(L, final_code, strlen(final_code), "=repl");
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// 情况 B: 看起来像语句 (字母开头),先尝试原样编译
|
||
|
|
status = luaL_loadbuffer(L, buffer, buffer_len, "=repl");
|
||
|
|
if (status == LUA_ERRSYNTAX)
|
||
|
|
{
|
||
|
|
lua_pop(L, 1); // 弹出旧错误
|
||
|
|
|
||
|
|
wrapped_code = RD_MALLOC(buffer_len + 10);
|
||
|
|
sprintf(wrapped_code, "return %s", buffer);
|
||
|
|
status = luaL_loadbuffer(L, wrapped_code, strlen(wrapped_code), "=repl");
|
||
|
|
|
||
|
|
if (status == LUA_ERRSYNTAX)
|
||
|
|
{
|
||
|
|
const char *new_err = lua_tostring(L, -1);
|
||
|
|
|
||
|
|
if (strstr(new_err, "<eof>") != NULL || strstr(new_err, "near 'if'") != NULL ||
|
||
|
|
strstr(new_err, "near 'function'") != NULL || strstr(new_err, "near 'for'") != NULL ||
|
||
|
|
strstr(new_err, "near 'while'") != NULL || strstr(new_err, "near 'do'") != NULL)
|
||
|
|
{
|
||
|
|
lua_pop(L, 1);
|
||
|
|
RD_FREE(wrapped_code);
|
||
|
|
wrapped_code = NULL;
|
||
|
|
incomplete = 1;
|
||
|
|
lua_print("%s", incomplete ? CONT_PROMPT : PROMPT);
|
||
|
|
return RD_FAILURE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (status == LUA_ERRSYNTAX)
|
||
|
|
{
|
||
|
|
const char *err_msg = lua_tostring(L, -1);
|
||
|
|
if (strstr(err_msg, "<eof>") != NULL || (strstr(err_msg, "'(' expected near") != NULL && looks_like_block))
|
||
|
|
{
|
||
|
|
incomplete = 1;
|
||
|
|
lua_print("%s", incomplete ? CONT_PROMPT : PROMPT);
|
||
|
|
lua_pop(L, 1);
|
||
|
|
if (wrapped_code)
|
||
|
|
{
|
||
|
|
RD_FREE(wrapped_code);
|
||
|
|
wrapped_code = NULL;
|
||
|
|
}
|
||
|
|
return RD_FAILURE;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
lua_print("Syntax Error: %s\n", err_msg);
|
||
|
|
lua_pop(L, 1);
|
||
|
|
incomplete = 0;
|
||
|
|
lua_print("%s", incomplete ? CONT_PROMPT : PROMPT);
|
||
|
|
RD_FREE(buffer); buffer = NULL; buffer_len = 0;
|
||
|
|
if (wrapped_code)
|
||
|
|
{
|
||
|
|
RD_FREE(wrapped_code);
|
||
|
|
wrapped_code = NULL;
|
||
|
|
}
|
||
|
|
return RD_FAILURE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (status != LUA_OK)
|
||
|
|
{
|
||
|
|
lua_print("Load Error: %s\n", lua_tostring(L, -1));
|
||
|
|
lua_pop(L, 1);
|
||
|
|
incomplete = 0;
|
||
|
|
lua_print("%s", incomplete ? CONT_PROMPT : PROMPT);
|
||
|
|
RD_FREE(buffer);
|
||
|
|
buffer = NULL;
|
||
|
|
buffer_len = 0;
|
||
|
|
if (wrapped_code)
|
||
|
|
{
|
||
|
|
RD_FREE(wrapped_code);
|
||
|
|
wrapped_code = NULL;
|
||
|
|
}
|
||
|
|
return RD_FAILURE;
|
||
|
|
}
|
||
|
|
|
||
|
|
status = lua_pcall(L, 0, LUA_MULTRET, 0);
|
||
|
|
if (status == LUA_OK)
|
||
|
|
{
|
||
|
|
print_result(L, status);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
const char *err_msg = lua_tostring(L, -1);
|
||
|
|
lua_print("%s\n", err_msg ? err_msg : "Unknown error");
|
||
|
|
lua_pop(L, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
incomplete = 0;
|
||
|
|
lua_print("%s", incomplete ? CONT_PROMPT : PROMPT);
|
||
|
|
RD_FREE(buffer);
|
||
|
|
buffer = NULL;
|
||
|
|
buffer_len = 0;
|
||
|
|
if (wrapped_code)
|
||
|
|
{
|
||
|
|
RD_FREE(wrapped_code);
|
||
|
|
wrapped_code = NULL;
|
||
|
|
}
|
||
|
|
return RD_SUCCESS;
|
||
|
|
|
||
|
|
cleanup:
|
||
|
|
if (wrapped_code)
|
||
|
|
{
|
||
|
|
RD_FREE(wrapped_code);
|
||
|
|
wrapped_code = NULL;
|
||
|
|
}
|
||
|
|
RD_FREE(buffer);
|
||
|
|
lua_close(L);
|
||
|
|
L = NULL;
|
||
|
|
lua_init(lua_print);
|
||
|
|
return iRet;
|
||
|
|
}
|
||
|
|
|
||
|
|
void luaprint_stdout(const char *fmt, ...)
|
||
|
|
{
|
||
|
|
va_list args;
|
||
|
|
va_start(args, fmt);
|
||
|
|
vprintf(fmt, args);
|
||
|
|
fflush(stdout);
|
||
|
|
va_end(args);
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef MAIN
|
||
|
|
#include <termios.h>
|
||
|
|
#include <unistd.h>
|
||
|
|
#include <errno.h>
|
||
|
|
|
||
|
|
int main(int argc, const char *argv[])
|
||
|
|
{
|
||
|
|
RD_INIT();
|
||
|
|
|
||
|
|
struct termios orig_termios;
|
||
|
|
struct termios raw_termios;
|
||
|
|
|
||
|
|
// 1. 获取当前终端设置
|
||
|
|
if (tcgetattr(STDIN_FILENO, &orig_termios) == -1) {
|
||
|
|
log_e("%s tcgetattr", strerror(errno));
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2. 复制一份用于修改
|
||
|
|
raw_termios = orig_termios;
|
||
|
|
|
||
|
|
// 3. 设置 Raw Mode
|
||
|
|
// 关闭规范模式 (ICANON) -> 禁用行缓冲,字符立即可读
|
||
|
|
// 关闭回显 (ECHO) -> 防止内核自动打印,由 readline 手动打印
|
||
|
|
// 关闭信号生成 (ISIG) -> Ctrl+C 不会被当成中断,而是作为普通字符读取 (可选,看你是否需要 Ctrl+C 退出)
|
||
|
|
raw_termios.c_lflag &= ~(ICANON | ECHO);
|
||
|
|
|
||
|
|
// 确保非阻塞或最小字符数设置 (可选,通常 fgetc 会阻塞直到有字符)
|
||
|
|
raw_termios.c_cc[VMIN] = 1;
|
||
|
|
raw_termios.c_cc[VTIME] = 0;
|
||
|
|
|
||
|
|
// 4. 应用新设置
|
||
|
|
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw_termios) == -1) {
|
||
|
|
log_e("%s tcsetattr", strerror(errno));
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
lua_init(luaprint_stdout);
|
||
|
|
|
||
|
|
while(1)
|
||
|
|
{
|
||
|
|
lua_repl(NULL, -1, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 5. 程序退出前恢复终端设置
|
||
|
|
tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios);
|
||
|
|
log_i("\nTerminal restored. Goodbye!\n");
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif
|