mirror of
https://github.com/QingdaoU/Judger.git
synced 2024-12-29 16:31:42 +00:00
Port to lua is written (#5)
Lua binding by @avaicode - Missing break between table and nil added - Fixed many small things int the port to Lua - Now it will check if args and env is a true list - Rename judge to run(the same as python's binding) - Removed a useless argument
This commit is contained in:
parent
9e290f6db6
commit
121cb2d089
21
bindings/Lua/LICENSE
Normal file
21
bindings/Lua/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Yanghe Sun
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
26
bindings/Lua/Makefile
Normal file
26
bindings/Lua/Makefile
Normal file
@ -0,0 +1,26 @@
|
||||
# Makefile for Judger's lua binding
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Werror -O3 -std=c99 -fPIC
|
||||
LDFLAGS ?= -pthread -lseccomp -fPIC -shared
|
||||
|
||||
JUDGER_OBJECTS = child.o killer.o logger.o runner.o rules/c_cpp.o rules/general.o
|
||||
OBJECTS = $(addprefix ../../src/,${JUDGER_OBJECTS}) judger.o
|
||||
|
||||
.PHONY: all test install clean
|
||||
|
||||
all: judger.so
|
||||
|
||||
judger.so: ${OBJECTS}
|
||||
${CC} ${OBJECTS} ${LDFLAGS} -o judger.so
|
||||
|
||||
install: all
|
||||
@mkdir -p /usr/local/lib/lua/5.3/
|
||||
@cp -f judger.so /usr/local/lib/lua/5.3/
|
||||
|
||||
clean:
|
||||
@rm -f ${OBJECTS} judger.so
|
||||
|
||||
%.o: %c
|
||||
${CC} ${CFLAGS} -o $@ -c $<
|
||||
|
223
bindings/Lua/judger.c
Normal file
223
bindings/Lua/judger.c
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
Lua Binding:
|
||||
The MIT License (MIT)
|
||||
Copyright (c) <2016> <avaicode>
|
||||
|
||||
Judger:
|
||||
The Star And Thank Author License (SATA)
|
||||
Copyright (c) <Qingdao University Online Judge Dev Team> <info@qduoj.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
Usage:
|
||||
In Lua: require "judger"
|
||||
In C: luaL_requiref(L, "judger", luaopen_judger, 1)
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <lua5.3/lua.h>
|
||||
#include <lua5.3/lauxlib.h>
|
||||
#include "../../src/runner.h"
|
||||
|
||||
typedef struct ConfItem {
|
||||
const char* name;
|
||||
int value;
|
||||
} ConfItem;
|
||||
static ConfItem conf_item[] = {
|
||||
{"VERSION", VERSION},
|
||||
{"UNLIMITED", UNLIMITED},
|
||||
{"RESULT_WRONG_ANSWER", WRONG_ANSWER},
|
||||
{"RESULT_SUCCESS", SUCCESS},
|
||||
{"RESULT_CPU_TIME_LIMIT_EXCEEDED", CPU_TIME_LIMIT_EXCEEDED},
|
||||
{"RESULT_REAL_TIME_LIMIT_EXCEEDED", REAL_TIME_LIMIT_EXCEEDED},
|
||||
{"RESULT_MEMORY_LIMIT_EXCEEDED", MEMORY_LIMIT_EXCEEDED},
|
||||
{"RESULT_RUNTIME_ERROR", RUNTIME_ERROR},
|
||||
{"RESULT_SYSTEM_ERROR", SYSTEM_ERROR},
|
||||
{"ERROR_INVALID_CONFIG", INVALID_CONFIG},
|
||||
{"ERROR_FORK_FAILED", FORK_FAILED},
|
||||
|
||||
{"ERROR_PTHREAD_FAILED", PTHREAD_FAILED},
|
||||
{"ERROR_WAIT_FAILED", WAIT_FAILED},
|
||||
{"ERROR_ROOT_REQUIRED", ROOT_REQUIRED},
|
||||
{"ERROR_LOAD_SECCOMP_FAILED", LOAD_SECCOMP_FAILED},
|
||||
{"ERROR_SETRLIMIT_FAILED", SETRLIMIT_FAILED},
|
||||
{"ERROR_DUP2_FAILED", DUP2_FAILED},
|
||||
{"ERROR_SETUID_FAILED", SETUID_FAILED},
|
||||
{"ERROR_EXECVE_FAILED", EXECVE_FAILED},
|
||||
{"ERROR_SPJ_ERROR", SPJ_ERROR}
|
||||
};
|
||||
static const int conf_item_size = sizeof(conf_item) / sizeof(ConfItem);
|
||||
|
||||
typedef struct ArgMask {
|
||||
const char* name;
|
||||
int t; //Should be lua_type
|
||||
int nil_accept;
|
||||
} ArgMask;
|
||||
static ArgMask arg_mask[] = {
|
||||
{"max_cpu_time", LUA_TNUMBER, 0},
|
||||
{"max_real_time", LUA_TNUMBER, 0},
|
||||
{"max_memory", LUA_TNUMBER, 0},
|
||||
{"max_process_number", LUA_TNUMBER, 0},
|
||||
{"max_output_size", LUA_TNUMBER, 0},
|
||||
{"exe_path", LUA_TSTRING, 0},
|
||||
{"input_path", LUA_TSTRING, 0},
|
||||
{"output_path", LUA_TSTRING, 0},
|
||||
{"error_path", LUA_TSTRING, 0},
|
||||
{"log_path", LUA_TSTRING, 0},
|
||||
{"seccomp_rule_name", LUA_TSTRING, 1},
|
||||
{"args", LUA_TTABLE, 0},
|
||||
{"env", LUA_TTABLE, 0},
|
||||
{"uid", LUA_TNUMBER, 0},
|
||||
{"gid", LUA_TNUMBER, 0}
|
||||
};
|
||||
static const int arg_mask_size = sizeof(arg_mask) / sizeof(ArgMask);
|
||||
|
||||
static int global_getconfig(lua_State* L);
|
||||
static int global_judge(lua_State* L);
|
||||
|
||||
static const struct luaL_Reg judger[] = {
|
||||
{"getconfig", global_getconfig},
|
||||
{"run", global_judge},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static char* _strdup(const char* s) {
|
||||
char* t = NULL;
|
||||
if (s && (t = (char*)malloc(strlen(s) + 1)))
|
||||
strcpy(t, s);
|
||||
return t;
|
||||
}
|
||||
|
||||
static int global_getconfig(lua_State* L) {
|
||||
int i = 0;
|
||||
|
||||
lua_createtable(L, 0, conf_item_size);
|
||||
for (; i < conf_item_size; ++i) {
|
||||
lua_pushstring(L, conf_item[i].name);
|
||||
lua_pushnumber(L, conf_item[i].value);
|
||||
lua_rawset(L, -3);
|
||||
}
|
||||
assert(lua_gettop(L) == 1 && lua_type(L, -1) == LUA_TTABLE); //One table left
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void destory_config(struct config* config) {
|
||||
int i = 0;
|
||||
|
||||
free(config->exe_path);
|
||||
free(config->input_path);
|
||||
free(config->output_path);
|
||||
free(config->error_path);
|
||||
free(config->log_path);
|
||||
free(config->seccomp_rule_name);
|
||||
|
||||
for (; i < 256; ++i) {
|
||||
free(config->args[i]);
|
||||
free(config->env[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int lua_checkstringtable(lua_State* L, char** dst, int max_size, int* dst_size) {
|
||||
int table_index = lua_gettop(L);
|
||||
int table_size = 0;
|
||||
|
||||
lua_pushnil(L);
|
||||
while (0 != lua_next(L, table_index)) {
|
||||
if (lua_type(L, -1) != LUA_TSTRING)
|
||||
return 0;
|
||||
if (lua_type(L, -2) != LUA_TNUMBER)
|
||||
return 0;
|
||||
|
||||
if (table_size == max_size)
|
||||
return 0;
|
||||
|
||||
dst[table_size] = _strdup(lua_tostring(L, -1));
|
||||
table_size++;
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if (dst_size != NULL)
|
||||
*dst_size = table_size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int global_judge(lua_State* L) {
|
||||
int i = 0, table_size = 0;
|
||||
struct config config;
|
||||
struct result result;
|
||||
void* arg_refs[arg_mask_size];
|
||||
|
||||
arg_refs[0] = &config.max_cpu_time;
|
||||
arg_refs[1] = &config.max_real_time;
|
||||
arg_refs[2] = &config.max_memory;
|
||||
arg_refs[3] = &config.max_process_number;
|
||||
arg_refs[4] = &config.max_output_size;
|
||||
arg_refs[5] = &config.exe_path;
|
||||
arg_refs[6] = &config.input_path;
|
||||
arg_refs[7] = &config.output_path;
|
||||
arg_refs[8] = &config.error_path;
|
||||
arg_refs[9] = &config.log_path;
|
||||
arg_refs[10] = &config.seccomp_rule_name;
|
||||
arg_refs[11] = &config.args;
|
||||
arg_refs[12] = &config.env;
|
||||
arg_refs[13] = &config.uid;
|
||||
arg_refs[14] = &config.gid;
|
||||
memset(&config, 0, sizeof(config));
|
||||
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
for (; i < arg_mask_size; ++i) {
|
||||
lua_pushstring(L, arg_mask[i].name);
|
||||
lua_gettable(L, -2);
|
||||
if (lua_type(L, -1) != arg_mask[i].t && !(arg_mask[i].nil_accept && lua_type(L, -1) == LUA_TNIL))
|
||||
return destory_config(&config), luaL_error(L, "bad argument %s", arg_mask[i].name);
|
||||
|
||||
|
||||
switch (lua_type(L, -1)) {
|
||||
case LUA_TNUMBER:
|
||||
*(int*)arg_refs[i] = lua_tointeger(L, -1);
|
||||
break;
|
||||
case LUA_TSTRING:
|
||||
*(char**)arg_refs[i] = _strdup(lua_tostring(L, -1));
|
||||
break;
|
||||
case LUA_TTABLE:
|
||||
if (lua_checkstringtable(L, (char**)arg_refs[i], 256 - 1, &table_size) == 0) {
|
||||
destory_config(&config);
|
||||
return luaL_error(L, "bad argument %s (item must be a string)", arg_mask[i].name);
|
||||
}
|
||||
*((char**)arg_refs[i] + table_size) = NULL;
|
||||
break;
|
||||
case LUA_TNIL:
|
||||
*(char**)arg_refs[i] = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
run(&config, &result);
|
||||
|
||||
lua_newtable(L);
|
||||
lua_pushstring(L, "cpu_time"); lua_pushnumber(L, result.cpu_time); lua_rawset(L, -3);
|
||||
lua_pushstring(L, "real_time"); lua_pushnumber(L, result.real_time); lua_rawset(L, -3);
|
||||
lua_pushstring(L, "memory"); lua_pushnumber(L, result.memory); lua_rawset(L, -3);
|
||||
lua_pushstring(L, "signal"); lua_pushnumber(L, result.signal); lua_rawset(L, -3);
|
||||
lua_pushstring(L, "exit_code"); lua_pushnumber(L, result.exit_code); lua_rawset(L, -3);
|
||||
lua_pushstring(L, "error"); lua_pushnumber(L, result.error); lua_rawset(L, -3);
|
||||
lua_pushstring(L, "result"); lua_pushnumber(L, result.result); lua_rawset(L, -3);
|
||||
assert(lua_gettop(L) == 2);
|
||||
|
||||
destory_config(&config);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int luaopen_judger(lua_State* L) {
|
||||
luaL_newlib(L, judger);
|
||||
return 1;
|
||||
}
|
Loading…
Reference in New Issue
Block a user