From 4cbf407d4fb8f2cda477de6b3526bf9895096171 Mon Sep 17 00:00:00 2001 From: Luna Date: Tue, 9 Apr 2019 20:47:58 +0200 Subject: [PATCH] Initial Commit --- .gitignore | 12 ++ LICENSE | 21 ++ README.md | 41 ++++ gmsv_file/premake5.lua | 76 ++++++++ gmsv_file/src/file.c | 105 ++++++++++ gmsv_file/src/file.h | 20 ++ gmsv_file/src/main.c | 129 +++++++++++++ include/GarrysMod/Lua/CCompat.cpp | 268 ++++++++++++++++++++++++++ include/GarrysMod/Lua/CCompat.h | 86 +++++++++ include/GarrysMod/Lua/Interface.h | 62 ++++++ include/GarrysMod/Lua/LuaBase.h | 275 +++++++++++++++++++++++++++ include/GarrysMod/Lua/SourceCompat.h | 28 +++ include/GarrysMod/Lua/Types.h | 130 +++++++++++++ include/GarrysMod/Lua/UserData.h | 18 ++ include/gmodc/lua/interface.h | 61 ++++++ include/gmodc/lua/lua.h | 20 ++ include/gmodc/lua/source_compat.h | 16 ++ include/gmodc/lua/types.h | 30 +++ 18 files changed, 1398 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 gmsv_file/premake5.lua create mode 100644 gmsv_file/src/file.c create mode 100644 gmsv_file/src/file.h create mode 100644 gmsv_file/src/main.c create mode 100644 include/GarrysMod/Lua/CCompat.cpp create mode 100644 include/GarrysMod/Lua/CCompat.h create mode 100644 include/GarrysMod/Lua/Interface.h create mode 100644 include/GarrysMod/Lua/LuaBase.h create mode 100644 include/GarrysMod/Lua/SourceCompat.h create mode 100644 include/GarrysMod/Lua/Types.h create mode 100644 include/GarrysMod/Lua/UserData.h create mode 100644 include/gmodc/lua/interface.h create mode 100644 include/gmodc/lua/lua.h create mode 100644 include/gmodc/lua/source_compat.h create mode 100644 include/gmodc/lua/types.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fe4ec69 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +.vscode +*/.vscode +gmsv_file/.vs/ +gmsv_file/Release/ +gmsv_file/Debug/ +gmsv_file/bin/ +gmsv_file/project/ +*.sln +*.vcxproj +*.vcproj +*.filters +*.user diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c218b2d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Luna D. + +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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3bc2268 --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# gmsv_file +A simple file i/o library for Garry's Mod written in ANSI C. + +## Installing +1. Go to the "Releases" of this GitHub repository. +2. Download the latest `.dll` file for your platform. +3. Copy that file to `garrysmod/lua/bin` of your server. + +## Building +1. Install premake5 +2. Use `premake5` followed by your platform (`vs2015` for windows, `gmake` for linux). +3. Navigate to the `project` folder. +4. If on Windows, open the `.sln` file, in on Linux, run `make`. +5. The compiled binary should be in the `gmsv_file/bin` folder. + +## Using +The module provides barebones functionality for file manipulation. It's being worked on, more features are coming soon! +(All functions are relative to `garrysmod/` folder!!) + +```lua +--- Appends contents at the end of file. +-- @return[Boolean success] +File.append(filename, contents) + +--- Deletes file. +-- @return[Boolean success] +File.delete(filename) + +--- Creates a folder with specified name. +-- Returns false if the folder exists, or was unable to be created. +-- @return[Boolean success] +File.mkdir(directory) + +--- Reads specified file. +-- @return[String contents] +File.read(filename) + +--- Writes contents to file. Overwrites existing contents. +-- @return[Boolean success] +File.write(filename, contents) +``` diff --git a/gmsv_file/premake5.lua b/gmsv_file/premake5.lua new file mode 100644 index 0000000..40210cf --- /dev/null +++ b/gmsv_file/premake5.lua @@ -0,0 +1,76 @@ +local config = { + garrysmod = '/home/example/server', + libname = 'gmsv_file_'..(os.target() == 'windows' and 'win32' or 'linux')..'.dll', + std = 'C89' +} + +local is_windows = os.target() == 'windows' +local is_linux = not is_windows +local ansi_c = string.lower(config.std) == 'c89' or string.lower(config.std) == 'ansi' +local suffix = is_windows and '_win' or '_linux' + +workspace 'file' + location './project' + configurations { 'x86', 'x86_64' } + flags { 'NoPCH', 'NoImportLib'} + symbols 'On' + editandcontinue 'Off' + vectorextensions 'SSE' + defines { 'NDEBUG' } + optimize 'Full' + floatingpoint 'Fast' + + -- Link stdlib statically for compatibility. + if is_linux then + linkoptions{ '-static-libstdc++', '-static-libgcc' } + else + staticruntime 'on' + end + + filter "configurations:x86" + architecture 'x86' + targetsuffix(suffix..(is_windows and '32' or '')) + + filter "configurations:x86_64" + architecture 'x86_64' + targetsuffix(suffix..'64') + +project 'file' + kind 'SharedLib' + language 'C' + location './project' + targetdir './bin' + -- libdirs { '../lib/'..string.lower(os.target()) } + includedirs { '../include' } + targetprefix 'gmsv_' + targetextension '.dll' + + if is_linux then + if ansi_c then + buildoptions { '-ansi', '-pedantic' } + end + + pic 'On' + end + + language 'C++' + files { '../include/GarrysMod/Lua/CCompat.cpp' } + language 'C' + files { + 'src/**.c', + 'src/**.h' + } + + --[[ + if is_windows then + links { } + else + links { } + end + --]] + + --[[ + postbuildcommands { + '{COPY} "%{cfg.buildtarget.abspath}" "'..config.garrysmod..'/garrysmod/lua/bin/'..config.libname..'"*', + } + ]] diff --git a/gmsv_file/src/file.c b/gmsv_file/src/file.c new file mode 100644 index 0000000..628d44e --- /dev/null +++ b/gmsv_file/src/file.c @@ -0,0 +1,105 @@ +#include "file.h" + +#ifdef _WIN32 +extern int getcwd(char *buf, size_t size); +extern int mkdir(const char *dirname); +#endif + +char* concat(const char *s1, const char *s2) { + char *result = malloc(strlen(s1) + strlen(s2) + 1); + strcpy(result, s1); + strcat(result, s2); + return result; +} + +void setup_directory(char **directory) { + char current_folder[256], *result; + getcwd(current_folder, sizeof(current_folder)); + result = concat(current_folder, "/garrysmod/"); + *directory = concat(result, *directory); + free(result); +} + +int file_write(const char *filename, void *data, size_t len) { + FILE *f; + char *fn = (char*)filename; + + setup_directory(&fn); + + f = fopen(fn, "wb"); + + if (f == NULL) { + return 0; + } + + fwrite(data, 1, len, f); + fclose(f); + + return 1; +} + +int file_append(const char *filename, void *data, size_t len) { + FILE *f; + char *fn = (char*)filename; + + setup_directory(&fn); + + f = fopen(fn, "ab"); + + if (f == NULL) { + return 0; + } + + fseek(f, 0, SEEK_END); + fwrite(data, 1, len, f); + fclose(f); + + return 1; +} + +int file_read(const char *filename, char **out) { + FILE *f; + int len; + char *buf, *fn = (char*)filename; + + setup_directory(&fn); + + f = fopen(fn, "rb"); + + if (f == NULL) { + return 0; + } + + fseek(f, 0L, SEEK_END); + len = ftell(f); + fseek(f, 0L, SEEK_SET); + buf = (char*)malloc(len + 1); + + if (!buf) { + fclose(f); + return 0; + } + + fread(buf, 1, len, f); + fclose(f); + + buf[len] = '\0'; + + *out = buf; + + return 1; +} + +int file_delete(const char *filename) { + char *fn = (char*)filename; + setup_directory(&fn); + + return remove(fn) == 0 ? 1 : 0; +} + +int file_mkdir(const char *dirname) { + char *fn = (char*)dirname; + setup_directory(&fn); + + return mkdir(fn) == 0 ? 1 : 0; +} \ No newline at end of file diff --git a/gmsv_file/src/file.h b/gmsv_file/src/file.h new file mode 100644 index 0000000..1d15423 --- /dev/null +++ b/gmsv_file/src/file.h @@ -0,0 +1,20 @@ +#ifndef GMSV_FILE_FILE_H +#define GMSV_FILE_FILE_H + +#include +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +int file_write(const char *filename, void *data, size_t len); +int file_append(const char *filename, void *data, size_t len); +int file_read(const char *filename, char **buffer); +int file_delete(const char *filename); +int file_mkdir(const char *dirname); + +#endif \ No newline at end of file diff --git a/gmsv_file/src/main.c b/gmsv_file/src/main.c new file mode 100644 index 0000000..0327007 --- /dev/null +++ b/gmsv_file/src/main.c @@ -0,0 +1,129 @@ +#include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#endif +#include +#include "file.h" + +LUA_FUNCTION(l_file_new) { + lua_push_string(LUA, "not implemented", 0); + + return 1; +} + +LUA_FUNCTION(l_file_write) { + char *contents; + + lua_check_type(LUA, 1, TYPE_STRING); + lua_check_type(LUA, 2, TYPE_STRING); + + contents = (char*)lua_get_string(LUA, 2, NULL); + + lua_push_bool(LUA, file_write(lua_get_string(LUA, 1, NULL), contents, strlen(contents))); + + return 1; +} + +LUA_FUNCTION(l_file_append) { + char *contents; + + lua_check_type(LUA, 1, TYPE_STRING); + lua_check_type(LUA, 2, TYPE_STRING); + + contents = (char*)lua_get_string(LUA, 2, NULL); + + lua_push_bool(LUA, file_append(lua_get_string(LUA, 1, NULL), contents, strlen(contents))); + + return 1; +} + +LUA_FUNCTION(l_file_read) { + char *buffer; + + lua_check_type(LUA, 1, TYPE_STRING); + + if (file_read(lua_get_string(LUA, 1, NULL), &buffer) != 1) { + lua_push_bool(LUA, 0); + return 1; + } + + lua_push_string(LUA, buffer, 0); + + free(buffer); + + return 1; +} + +LUA_FUNCTION(l_file_delete) { + lua_check_type(LUA, 1, TYPE_STRING); + + lua_push_bool(LUA, file_delete(lua_get_string(LUA, 1, NULL))); + + return 1; +} + +LUA_FUNCTION(l_file_mkdir) { + lua_check_type(LUA, 1, TYPE_STRING); + + lua_push_bool(LUA, file_mkdir(lua_get_string(LUA, 1, NULL))); + + return 1; +} + +GMOD_MODULE_OPEN() { + int global_r, file_r; + + lua_push_special(LUA, LUA_SPECIAL_GLOB); + global_r = lua_reference_create(LUA); + + lua_create_table(LUA); + file_r = lua_reference_create(LUA); + + lua_reference_push(LUA, file_r); + lua_push_string(LUA, "open", 0); + lua_push_cfunc(LUA, l_file_new); + lua_set_table(LUA, -3); + + lua_reference_push(LUA, file_r); + lua_push_string(LUA, "write", 0); + lua_push_cfunc(LUA, l_file_write); + lua_set_table(LUA, -3); + + lua_reference_push(LUA, file_r); + lua_push_string(LUA, "read", 0); + lua_push_cfunc(LUA, l_file_read); + lua_set_table(LUA, -3); + + lua_reference_push(LUA, file_r); + lua_push_string(LUA, "append", 0); + lua_push_cfunc(LUA, l_file_append); + lua_set_table(LUA, -3); + + lua_reference_push(LUA, file_r); + lua_push_string(LUA, "delete", 0); + lua_push_cfunc(LUA, l_file_delete); + lua_set_table(LUA, -3); + + lua_reference_push(LUA, file_r); + lua_push_string(LUA, "mkdir", 0); + lua_push_cfunc(LUA, l_file_mkdir); + lua_set_table(LUA, -3); + + lua_reference_push(LUA, global_r); + lua_push_string(LUA, "File", 0); + lua_reference_push(LUA, file_r); + lua_set_table(LUA, -3); + lua_reference_free(LUA, file_r); + + lua_reference_free(LUA, global_r); + + return 0; +} + +GMOD_MODULE_CLOSE() { + return 0; +} diff --git a/include/GarrysMod/Lua/CCompat.cpp b/include/GarrysMod/Lua/CCompat.cpp new file mode 100644 index 0000000..df23177 --- /dev/null +++ b/include/GarrysMod/Lua/CCompat.cpp @@ -0,0 +1,268 @@ +#include +#include "LuaBase.h" +#include "Interface.h" +#include "CCompat.h" + +#define GET_LUABASE(l) \ + GarrysMod::Lua::ILuaBase *l = (GarrysMod::Lua::ILuaBase*)(L); + +luabase_t *lua_get_base(lua_State *L) { + return (luabase_t*)L->luabase; +} + +int lua_top(luabase_t *L) { + GET_LUABASE(l) + return l->Top(); +} + +void lua_push(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + l->Push(stack_pos); +} + +void lua_pop(luabase_t *L, int amt) { + GET_LUABASE(l) + l->Pop(amt); +} + +void lua_get_table(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + l->GetTable(stack_pos); +} + +void lua_get_field(luabase_t *L, int stack_pos, const char *name) { + GET_LUABASE(l) + l->GetField(stack_pos, name); +} + +void lua_set_field(luabase_t *L, int stack_pos, const char *name) { + GET_LUABASE(l) + l->SetField(stack_pos, name); +} + +void lua_create_table(luabase_t *L) { + GET_LUABASE(l) + l->CreateTable(); +} + +void lua_set_table(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + l->SetTable(stack_pos); +} + +void lua_set_meta_table(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + l->SetMetaTable(stack_pos); +} + +void lua_get_meta_table(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + l->GetMetaTable(stack_pos); +} + +void lua_call(luabase_t *L, int args, int results) { + GET_LUABASE(l) + l->Call(args, results); +} + +int lua_pcall(luabase_t *L, int args, int results, int error_func) { + GET_LUABASE(l) + return l->PCall(args, results, error_func); +} + +int lua_equal(luabase_t *L, int a, int b) { + GET_LUABASE(l) + return l->Equal(a, b); +} + +int lua_raw_equal(luabase_t *L, int a, int b) { + GET_LUABASE(l) + return l->RawEqual(a, b); +} + +void lua_insert(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + l->Insert(stack_pos); +} + +void lua_remove(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + l->Remove(stack_pos); +} + +int lua_next(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + return l->Next(stack_pos); +} + +void lua_throw_error(luabase_t *L, const char *message) { + GET_LUABASE(l) + l->ThrowError(message); +} + +void lua_check_type(luabase_t *L, int stack_pos, int type) { + GET_LUABASE(l) + l->CheckType(stack_pos, type); +} + +void lua_arg_error(luabase_t *L, int arg_num, const char *message) { + GET_LUABASE(l) + l->ArgError(arg_num, message); +} + +void lua_raw_get(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + l->RawGet(stack_pos); +} + +void lua_raw_set(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + l->RawSet(stack_pos); +} + +const char* lua_get_string(luabase_t *L, int stack_pos, unsigned int *out_len) { + GET_LUABASE(l) + return l->GetString(stack_pos, out_len); +} + +double lua_get_number(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + return l->GetNumber(stack_pos); +} + +int lua_get_bool(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + return (int)l->GetBool(stack_pos); +} + +cfunc_t lua_get_cfunc(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + return (cfunc_t)l->GetCFunction(stack_pos); +} + +void lua_push_nil(luabase_t *L) { + GET_LUABASE(l) + l->PushNil(); +} + +void lua_push_string(luabase_t *L, const char *val, unsigned int len) { + GET_LUABASE(l) + l->PushString(val, len); +} + +void lua_push_number(luabase_t *L, double val) { + GET_LUABASE(l) + l->PushNumber(val); +} + +void lua_push_bool(luabase_t *L, int val) { + GET_LUABASE(l) + l->PushBool((bool)val); +} + +void lua_push_cfunc(luabase_t *L, cfunc_t val) { + GET_LUABASE(l) + l->PushCFunction((GarrysMod::Lua::CFunc)val); +} + +void lua_push_cclosure(luabase_t *L, cfunc_t val, int vars) { + GET_LUABASE(l) + l->PushCClosure((GarrysMod::Lua::CFunc)val, vars); +} + +void lua_push_userdata(luabase_t *L, void *val) { + GET_LUABASE(l) + l->PushUserdata(val); +} + +int lua_reference_create(luabase_t *L) { + GET_LUABASE(l) + return l->ReferenceCreate(); +} + +void lua_reference_free(luabase_t *L, int ref) { + GET_LUABASE(l) + l->ReferenceFree(ref); +} + +void lua_reference_push(luabase_t *L, int ref) { + GET_LUABASE(l) + l->ReferencePush(ref); +} + +void lua_push_special(luabase_t *L, int type) { + GET_LUABASE(l) + l->PushSpecial(type); +} + +int lua_is_type(luabase_t *L, int stack_pos, int type) { + GET_LUABASE(l) + return l->IsType(stack_pos, type); +} + +const char* lua_get_type_name(luabase_t *L, int type) { + GET_LUABASE(l) + return l->GetTypeName(type); +} + +const char* lua_check_string(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + return l->CheckString(stack_pos); +} + +double lua_check_number(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + return l->CheckNumber(stack_pos); +} + +int lua_obj_len(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + return l->ObjLen(stack_pos); +} + +/* +const QAngle *lua_get_angle(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + return l->GetAngle(stack_pos); +} + +const Vector *lua_get_vector(luabase_t *L, int stack_pos) { + GET_LUABASE(l) + return *l->GetVector(stack_pos); +} + +void lua_push_angle(luabase_t *L, QAngle val) { + GET_LUABASE(l) + l->PushAngle(&val); +} + +void lua_push_vector(luabase_t *L, Vector val) { + GET_LUABASE(l) + l->PushVector(val); +} +*/ + +void lua_set_state(luabase_t *L, lua_State *state) { + GET_LUABASE(l) + l->SetState(state); +} + +int lua_create_meta_table(luabase_t *L, const char *name) { + GET_LUABASE(l) + return l->CreateMetaTable(name); +} + +int lua_push_meta_table(luabase_t *L, int type) { + GET_LUABASE(l) + return l->PushMetaTable(type); +} + +void lua_push_user_type(luabase_t *L, void *data, int type) { + GET_LUABASE(l) + l->PushUserType(data, type); +} + +void lua_set_user_type(luabase_t *L, int stack_pos, void *data) { + GET_LUABASE(l) + l->SetUserType(stack_pos, data); +} diff --git a/include/GarrysMod/Lua/CCompat.h b/include/GarrysMod/Lua/CCompat.h new file mode 100644 index 0000000..099bd0e --- /dev/null +++ b/include/GarrysMod/Lua/CCompat.h @@ -0,0 +1,86 @@ +#ifndef GARRYSMOD_LUA_CCOMPAT_H +#define GARRYSMOD_LUA_CCOMPAT_H + +#include +#include +#include + +#ifdef __cplusplus +#include "LuaBase.h" +#include "SourceCompat.h" +extern "C" { +#endif + + typedef void luabase_t; + + typedef struct { + void *data; + unsigned char type; + } userdata_t; + + typedef int (*cfunc_t)(lua_State *L); + + /* + For documentation, please refer to ./include/GarrysMod/Lua/LuaBase.h + */ + + luabase_t *lua_get_base(lua_State *L); + int lua_top(luabase_t *L); + void lua_push(luabase_t *L, int stack_pos); + void lua_pop(luabase_t *L, int amt); + void lua_get_table(luabase_t *L, int stack_pos); + void lua_get_field(luabase_t *L, int stack_pos, const char *name); + void lua_set_field(luabase_t *L, int stack_pos, const char *name); + void lua_create_table(luabase_t *L); + void lua_set_table(luabase_t *L, int stack_pos); + void lua_set_meta_table(luabase_t *L, int stack_pos); + void lua_get_meta_table(luabase_t *L, int stack_pos); + void lua_call(luabase_t *L, int args, int results); + int lua_pcall(luabase_t *L, int args, int results, int error_func); + int lua_equal(luabase_t *L, int a, int b); + int lua_raw_equal(luabase_t *L, int a, int b); + void lua_insert(luabase_t *L, int stack_pos); + void lua_remove(luabase_t *L, int stack_pos); + int lua_next(luabase_t *L, int stack_pos); + void lua_throw_error(luabase_t *L, const char *message); + void lua_check_type(luabase_t *L, int stack_pos, int type); + void lua_arg_error(luabase_t *L, int arg_num, const char *message); + void lua_raw_get(luabase_t *L, int stack_pos); + void lua_raw_set(luabase_t *L, int stack_pos); + const char* lua_get_string(luabase_t *L, int stack_pos, unsigned int *out_len); + double lua_get_number(luabase_t *L, int stack_pos); + int lua_get_bool(luabase_t *L, int stack_pos); + cfunc_t lua_get_cfunc(luabase_t *L, int stack_pos); + void lua_push_nil(luabase_t *L); + void lua_push_string(luabase_t *L, const char *val, unsigned int len); + void lua_push_number(luabase_t *L, double val); + void lua_push_bool(luabase_t *L, int val); + void lua_push_cfunc(luabase_t *L, cfunc_t val); + void lua_push_cclosure(luabase_t *L, cfunc_t val, int vars); + void lua_push_userdata(luabase_t *L, void *val); + int lua_reference_create(luabase_t *L); + void lua_reference_free(luabase_t *L, int ref); + void lua_reference_push(luabase_t *L, int ref); + void lua_push_special(luabase_t *L, int type); + int lua_is_type(luabase_t *L, int stack_pos, int type); + const char* lua_get_type_name(luabase_t *L, int type); + const char* lua_check_string(luabase_t *L, int stack_pos); + double lua_check_number(luabase_t *L, int stack_pos); + int lua_obj_len(luabase_t *L, int stack_pos); + /* + const QAngle *lua_get_angle(luabase_t *L, int stack_pos); + const Vector *lua_get_vector(luabase_t *L, int stack_pos); + void lua_push_angle(luabase_t *L, QAngle *val); + void lua_push_vector(luabase_t *L, Vector *val); + */ + void lua_set_state(luabase_t *L, lua_State *state); + int lua_create_meta_table(luabase_t *L, const char *name); + int lua_push_meta_table(luabase_t *L, int type); + void lua_push_user_type(luabase_t *L, void *data, int type); + void lua_set_user_type(luabase_t *L, int stack_pos, void *data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/GarrysMod/Lua/Interface.h b/include/GarrysMod/Lua/Interface.h new file mode 100644 index 0000000..06c9c96 --- /dev/null +++ b/include/GarrysMod/Lua/Interface.h @@ -0,0 +1,62 @@ +#ifndef GARRYSMOD_LUA_INTERFACE_H +#define GARRYSMOD_LUA_INTERFACE_H + +#include "LuaBase.h" + +struct lua_State +{ +#if defined(__x86_64__) || defined(_M_X64) + unsigned char _ignore_this_common_lua_header_[92 + 22]; +#elif defined(__i386) || defined(_M_IX86) + unsigned char _ignore_this_common_lua_header_[48 + 22]; +#else +#error Unknown architecture detected +#endif + + GarrysMod::Lua::ILuaBase *luabase; +}; + +#ifndef GMOD +#ifdef _WIN32 +#define DLL_EXPORT extern "C" __declspec(dllexport) +#else +#define DLL_EXPORT extern "C" __attribute__((visibility("default"))) +#endif + +#ifdef GMOD_ALLOW_DEPRECATED +// Stop using this and use LUA_FUNCTION! +#define LUA (state->luabase) + +#define GMOD_MODULE_OPEN() DLL_EXPORT int gmod13_open(lua_State *state) +#define GMOD_MODULE_CLOSE() DLL_EXPORT int gmod13_close(lua_State *state) +#else +#define GMOD_MODULE_OPEN() \ + int gmod13_open__Imp(GarrysMod::Lua::ILuaBase *LUA); \ + DLL_EXPORT int gmod13_open(lua_State *L) \ + { \ + return gmod13_open__Imp(L->luabase); \ + } \ + int gmod13_open__Imp(GarrysMod::Lua::ILuaBase *LUA) + +#define GMOD_MODULE_CLOSE() \ + int gmod13_close__Imp(GarrysMod::Lua::ILuaBase *LUA); \ + DLL_EXPORT int gmod13_close(lua_State *L) \ + { \ + return gmod13_close__Imp(L->luabase); \ + } \ + int gmod13_close__Imp(GarrysMod::Lua::ILuaBase *LUA) + +#define LUA_FUNCTION(FUNC) \ + int FUNC##__Imp(GarrysMod::Lua::ILuaBase *LUA); \ + int FUNC(lua_State *L) \ + { \ + GarrysMod::Lua::ILuaBase *LUA = L->luabase; \ + LUA->SetState(L); \ + return FUNC##__Imp(LUA); \ + } \ + int FUNC##__Imp(GarrysMod::Lua::ILuaBase *LUA) +#endif + +#endif + +#endif diff --git a/include/GarrysMod/Lua/LuaBase.h b/include/GarrysMod/Lua/LuaBase.h new file mode 100644 index 0000000..b261c40 --- /dev/null +++ b/include/GarrysMod/Lua/LuaBase.h @@ -0,0 +1,275 @@ +#ifndef GARRYSMOD_LUA_LUABASE_H +#define GARRYSMOD_LUA_LUABASE_H + +#include + +#include "Types.h" +#include "UserData.h" +#include "SourceCompat.h" + +struct lua_State; + +namespace GarrysMod +{ +namespace Lua +{ +typedef int (*CFunc)(lua_State *L); + +// +// Use this to communicate between C and Lua +// +class ILuaBase +{ +public: + // You shouldn't need to use this struct + // Instead, use the UserType functions + struct UserData + { + void *data; + unsigned char type; + }; + + // Returns the amount of values on the stack + virtual int Top(void) = 0; + + // Pushes a copy of the value at iStackPos to the top of the stack + virtual void Push(int iStackPos) = 0; + + // Pops iAmt values from the top of the stack + virtual void Pop(int iAmt = 1) = 0; + + // Pushes table[key] on to the stack + // table = value at iStackPos + // key = value at top of the stack + virtual void GetTable(int iStackPos) = 0; + + // Pushes table[key] on to the stack + // table = value at iStackPos + // key = strName + virtual void GetField(int iStackPos, const char *strName) = 0; + + // Sets table[key] to the value at the top of the stack + // table = value at iStackPos + // key = strName + // Pops the value from the stack + virtual void SetField(int iStackPos, const char *strName) = 0; + + // Creates a new table and pushes it to the top of the stack + virtual void CreateTable() = 0; + + // Sets table[key] to the value at the top of the stack + // table = value at iStackPos + // key = value 2nd to the top of the stack + // Pops the key and the value from the stack + virtual void SetTable(int iStackPos) = 0; + + // Sets the metatable for the value at iStackPos to the value at the top of the stack + // Pops the value off of the top of the stack + virtual void SetMetaTable(int iStackPos) = 0; + + // Pushes the metatable of the value at iStackPos on to the top of the stack + // Upon failure, returns false and does not push anything + virtual bool GetMetaTable(int i) = 0; + + // Calls a function + // To use it: Push the function on to the stack followed by each argument + // Pops the function and arguments from the stack, leaves iResults values on the stack + // If this function errors, any local C values will not have their destructors called! + virtual void Call(int iArgs, int iResults) = 0; + + // Similar to Call + // See: lua_pcall( lua_State*, int, int, int ) + virtual int PCall(int iArgs, int iResults, int iErrorFunc) = 0; + + // Returns true if the values at iA and iB are equal + virtual int Equal(int iA, int iB) = 0; + + // Returns true if the value at iA and iB are equal + // Does not invoke metamethods + virtual int RawEqual(int iA, int iB) = 0; + + // Moves the value at the top of the stack in to iStackPos + // Any elements above iStackPos are shifted upwards + virtual void Insert(int iStackPos) = 0; + + // Removes the value at iStackPos from the stack + // Any elements above iStackPos are shifted downwards + virtual void Remove(int iStackPos) = 0; + + // Allows you to iterate tables similar to pairs(...) + // See: lua_next( lua_State*, int ); + virtual int Next(int iStackPos) = 0; + +#ifndef GMOD_ALLOW_DEPRECATED +private: +#endif + // Deprecated: Use the UserType functions instead of this + virtual void *NewUserdata(unsigned int iSize) = 0; + +public: + // Throws an error and ceases execution of the function + // If this function is called, any local C values will not have their destructors called! + virtual void ThrowError(const char *strError) = 0; + + // Checks that the type of the value at iStackPos is iType + // Throws and error and ceases execution of the function otherwise + // If this function errors, any local C values will not have their destructors called! + virtual void CheckType(int iStackPos, int iType) = 0; + + // Throws a pretty error message about the given argument + // If this function is called, any local C values will not have their destructors called! + virtual void ArgError(int iArgNum, const char *strMessage) = 0; + + // Pushes table[key] on to the stack + // table = value at iStackPos + // key = value at top of the stack + // Does not invoke metamethods + virtual void RawGet(int iStackPos) = 0; + + // Sets table[key] to the value at the top of the stack + // table = value at iStackPos + // key = value 2nd to the top of the stack + // Pops the key and the value from the stack + // Does not invoke metamethods + virtual void RawSet(int iStackPos) = 0; + + // Returns the string at iStackPos. iOutLen is set to the length of the string if it is not NULL + // If the value at iStackPos is a number, it will be converted in to a string + // Returns NULL upon failure + virtual const char *GetString(int iStackPos = -1, unsigned int *iOutLen = NULL) = 0; + + // Returns the number at iStackPos + // Returns 0 upon failure + virtual double GetNumber(int iStackPos = -1) = 0; + + // Returns the boolean at iStackPos + // Returns false upon failure + virtual bool GetBool(int iStackPos = -1) = 0; + + // Returns the C-Function at iStackPos + // returns NULL upon failure + virtual CFunc GetCFunction(int iStackPos = -1) = 0; + +#ifndef GMOD_ALLOW_DEPRECATED +private: +#endif + // Deprecated: You should probably be using the UserType functions instead of this + virtual void *GetUserdata(int iStackPos = -1) = 0; + +public: + // Pushes a nil value on to the stack + virtual void PushNil() = 0; + + // Pushes the given string on to the stack + // If iLen is 0, strlen will be used to determine the string's length + virtual void PushString(const char *val, unsigned int iLen = 0) = 0; + + // Pushes the given double on to the stack + virtual void PushNumber(double val) = 0; + + // Pushes the given bobolean on to the stack + virtual void PushBool(bool val) = 0; + + // Pushes the given C-Function on to the stack + virtual void PushCFunction(CFunc val) = 0; + + // Pushes the given C-Function on to the stack with upvalues + // See: GetUpvalueIndex() + virtual void PushCClosure(CFunc val, int iVars) = 0; + + // Pushes the given pointer on to the stack as light-userdata + virtual void PushUserdata(void *) = 0; + + // Allows for values to be stored by reference for later use + // Make sure you call ReferenceFree when you are done with a reference + virtual int ReferenceCreate() = 0; + virtual void ReferenceFree(int i) = 0; + virtual void ReferencePush(int i) = 0; + + // Push a special value onto the top of the stack (see SPECIAL_* enums) + virtual void PushSpecial(int iType) = 0; + + // Returns true if the value at iStackPos is of type iType + // See: Types.h + virtual bool IsType(int iStackPos, int iType) = 0; + + // Returns the type of the value at iStackPos + // See: Types.h + virtual int GetType(int iStackPos) = 0; + + // Returns the name associated with the given type ID + // See: Types.h + // Note: GetTypeName does not work with user-created types + virtual const char *GetTypeName(int iType) = 0; + +#ifndef GMOD_ALLOW_DEPRECATED +private: +#endif + // Deprecated: Use CreateMetaTable + virtual void CreateMetaTableType(const char *strName, int iType) = 0; + +public: + // Like Get* but throws errors and returns if they're not of the expected type + // If these functions error, any local C values will not have their destructors called! + virtual const char *CheckString(int iStackPos = -1) = 0; + virtual double CheckNumber(int iStackPos = -1) = 0; + + // Returns the length of the object at iStackPos + // Works for: strings, tables, userdata + virtual int ObjLen(int iStackPos = -1) = 0; + + // Returns the angle at iStackPos + virtual const QAngle &GetAngle(int iStackPos = -1) = 0; + + // Returns the vector at iStackPos + virtual const Vector &GetVector(int iStackPos = -1) = 0; + + // Pushes the given angle to the top of the stack + virtual void PushAngle(const QAngle &val) = 0; + + // Pushes the given vector to the top of the stack + virtual void PushVector(const Vector &val) = 0; + + // Sets the lua_State to be used by the ILuaBase implementation + // You don't need to use this if you use the LUA_FUNCTION macro + virtual void SetState(lua_State *L) = 0; + + // Pushes the metatable associated with the given type name + // Returns the type ID to use for this type + // If the type doesn't currently exist, it will be created + virtual int CreateMetaTable(const char *strName) = 0; + + // Pushes the metatable associated with the given type + virtual bool PushMetaTable(int iType) = 0; + + // Creates a new UserData of type iType that references the given data + virtual void PushUserType(void *data, int iType) = 0; + + // Sets the data pointer of the UserType at iStackPos + // You can use this to invalidate a UserType by passing NULL + virtual void SetUserType(int iStackPos, void *data) = 0; + + // Returns the data of the UserType at iStackPos if it is of the given type + template + T *GetUserType(int iStackPos, int iType) + { + UserData *ud = (UserData *)GetUserdata(iStackPos); + + if (ud == NULL || ud->data == NULL || ud->type != iType) + return NULL; + + return reinterpret_cast(ud->data); + } +}; + +// For use with ILuaBase::PushSpecial +enum +{ + SPECIAL_GLOB, // Global table + SPECIAL_ENV, // Environment table + SPECIAL_REG // Registry table +}; +} // namespace Lua +} // namespace GarrysMod + +#endif diff --git a/include/GarrysMod/Lua/SourceCompat.h b/include/GarrysMod/Lua/SourceCompat.h new file mode 100644 index 0000000..15712a5 --- /dev/null +++ b/include/GarrysMod/Lua/SourceCompat.h @@ -0,0 +1,28 @@ +#ifndef GARRYSMOD_LUA_SOURCECOMPAT_H +#define GARRYSMOD_LUA_SOURCECOMPAT_H + +#ifdef GMOD_USE_SOURCESDK +#include "mathlib/vector.h" +#else +struct Vector +{ + Vector() + : x(0.f), y(0.f), z(0.f) + { + } + + float x, y, z; +}; + +struct QAngle +{ + QAngle() + : x(0.f), y(0.f), z(0.f) + { + } + + float x, y, z; +}; +#endif + +#endif diff --git a/include/GarrysMod/Lua/Types.h b/include/GarrysMod/Lua/Types.h new file mode 100644 index 0000000..dbddf56 --- /dev/null +++ b/include/GarrysMod/Lua/Types.h @@ -0,0 +1,130 @@ +#ifndef GARRYSMOD_LUA_TYPES_H +#define GARRYSMOD_LUA_TYPES_H + +#ifdef ENTITY +#undef ENTITY +#endif + +#ifdef VECTOR +#undef VECTOR +#endif + +namespace GarrysMod +{ +namespace Lua +{ +namespace Type +{ +enum +{ +#ifdef GMOD_ALLOW_DEPRECATED + // Deprecated: Use NONE instead of INVALID + INVALID = -1, +#endif + + // Lua Types + NONE = -1, + NIL, + BOOL, + LIGHTUSERDATA, + NUMBER, + STRING, + TABLE, + FUNCTION, + USERDATA, + THREAD, + + // GMod Types + ENTITY, + VECTOR, + ANGLE, + PHYSOBJ, + SAVE, + RESTORE, + DAMAGEINFO, + EFFECTDATA, + MOVEDATA, + RECIPIENTFILTER, + USERCMD, + SCRIPTEDVEHICLE, + MATERIAL, + PANEL, + PARTICLE, + PARTICLEEMITTER, + TEXTURE, + USERMSG, + CONVAR, + IMESH, + MATRIX, + SOUND, + PIXELVISHANDLE, + DLIGHT, + VIDEO, + FILE, + LOCOMOTION, + PATH, + NAVAREA, + SOUNDHANDLE, + NAVLADDER, + PARTICLESYSTEM, + PROJECTEDTEXTURE, + PHYSCOLLIDE, + + COUNT +}; + +#if (defined(GMOD) || defined(GMOD_ALLOW_DEPRECATED)) +// You should use ILuaBase::GetTypeName instead of directly accessing this array +static const char *Name[] = + { + "nil", + "bool", + "lightuserdata", + "number", + "string", + "table", + "function", + "userdata", + "thread", + "entity", + "vector", + "angle", + "physobj", + "save", + "restore", + "damageinfo", + "effectdata", + "movedata", + "recipientfilter", + "usercmd", + "vehicle", + "material", + "panel", + "particle", + "particleemitter", + "texture", + "usermsg", + "convar", + "mesh", + "matrix", + "sound", + "pixelvishandle", + "dlight", + "video", + "file", + "locomotion", + "path", + "navarea", + "soundhandle", + "navladder", + "particlesystem", + "projectedtexture", + "physcollide", + + 0}; +#endif +} // namespace Type +} // namespace Lua +} // namespace GarrysMod + +#endif diff --git a/include/GarrysMod/Lua/UserData.h b/include/GarrysMod/Lua/UserData.h new file mode 100644 index 0000000..b19c0f2 --- /dev/null +++ b/include/GarrysMod/Lua/UserData.h @@ -0,0 +1,18 @@ +#ifndef GARRYSMOD_LUA_USERDATA_H +#define GARRYSMOD_LUA_USERDATA_H + +#ifdef GMOD_ALLOW_DEPRECATED +namespace GarrysMod +{ +namespace Lua +{ +struct UserData +{ + void *data; + unsigned char type; +}; +} // namespace Lua +} // namespace GarrysMod +#endif + +#endif diff --git a/include/gmodc/lua/interface.h b/include/gmodc/lua/interface.h new file mode 100644 index 0000000..3964a6b --- /dev/null +++ b/include/gmodc/lua/interface.h @@ -0,0 +1,61 @@ +#ifndef GMODC_LUA_INTERFACE_H +#define GMODC_LUA_INTERFACE_H + +#include +#include "source_compat.h" +#include "types.h" +#include "lua.h" + +enum { + LUA_SPECIAL_GLOB, /* Global table */ + LUA_SPECIAL_ENV, /* Environment table */ + LUA_SPECIAL_REG /* Registry table */ +}; + +#ifndef GMOD +#ifdef _WIN32 +#define DLL_EXPORT __declspec(dllexport) +#else +#define DLL_EXPORT __attribute__((visibility("default"))) +#endif + +#ifdef GMOD_MODULE_OPEN +#undef GMOD_MODULE_OPEN +#endif + +#ifdef GMOD_MODULE_CLOSE +#undef GMOD_MODULE_CLOSE +#endif + +#ifdef LUA_FUNCTION +#undef LUA_FUNCTION +#endif + +#define GMOD_MODULE_OPEN() \ + int gmod13_open__Imp(luabase_t *LUA); \ + DLL_EXPORT int gmod13_open(lua_State *L) \ + { \ + return gmod13_open__Imp(lua_get_base(L)); \ + } \ + int gmod13_open__Imp(luabase_t *LUA) + +#define GMOD_MODULE_CLOSE() \ + int gmod13_close__Imp(luabase_t *LUA); \ + DLL_EXPORT int gmod13_close(lua_State *L) \ + { \ + return gmod13_close__Imp(lua_get_base(L)); \ + } \ + int gmod13_close__Imp(luabase_t *LUA) + +#define LUA_FUNCTION(FUNC) \ + int FUNC##__Imp(luabase_t *LUA); \ + int FUNC(lua_State *L) \ + { \ + luabase_t *LUA = lua_get_base(L); \ + lua_set_state(LUA, L); \ + return FUNC##__Imp(LUA); \ + } \ + int FUNC##__Imp(luabase_t *LUA) +#endif + +#endif diff --git a/include/gmodc/lua/lua.h b/include/gmodc/lua/lua.h new file mode 100644 index 0000000..351c352 --- /dev/null +++ b/include/gmodc/lua/lua.h @@ -0,0 +1,20 @@ +#ifndef GMODC_LUA_LUA_H +#define GMODC_LUA_LUA_H + +#ifndef GARRYSMOD_LUA_INTERFACE_H + +typedef struct { +#if defined(__x86_64__) || defined(_M_X64) + unsigned char _ignore_this_common_lua_header_[92 + 22]; +#elif defined(__i386) || defined(_M_IX86) + unsigned char _ignore_this_common_lua_header_[48 + 22]; +#else +#error Unknown architecture detected +#endif + + void *luabase; +} lua_State; + +#endif + +#endif diff --git a/include/gmodc/lua/source_compat.h b/include/gmodc/lua/source_compat.h new file mode 100644 index 0000000..bed89c9 --- /dev/null +++ b/include/gmodc/lua/source_compat.h @@ -0,0 +1,16 @@ +#ifndef GMODC_LUA_SOURCE_COMPAT_H +#define GMODC_LUA_SOURCE_COMPAT_H + +#ifndef GARRYSMOD_LUA_SOURCECOMPAT_H + +typedef struct { + float x, y, z; +} Vector; + +typedef struct { + float x, y, z; +} QAngle; + +#endif + +#endif diff --git a/include/gmodc/lua/types.h b/include/gmodc/lua/types.h new file mode 100644 index 0000000..0c5272f --- /dev/null +++ b/include/gmodc/lua/types.h @@ -0,0 +1,30 @@ +#ifndef GMODC_LUA_TYPES_H +#define GMODC_LUA_TYPES_H + +#ifdef ENTITY +#undef ENTITY +#endif + +#ifdef VECTOR +#undef VECTOR +#endif + +#define GMODC_TYPES(_) \ + /* Lua Types */ \ + _(NIL) _(BOOL) _(LIGHTUSERDATA) _(NUMBER) _(STRING) _(TABLE) _(FUNCTION) _(USERDATA) _(THREAD) \ + /* Gmod Types */ \ + _(ENTITY) _(VECTOR) _(ANGLE) _(PHYSOBJ) _(SAVE) _(RESTORE) _(DAMAGEINFO) _(EFFECTDATA) \ + _(MOVEDATA) _(RECIPIENTFILTER) _(USERCMD) _(SCRIPTEDVEHICLE) _(MATERIAL) _(PANEL) \ + _(PARTICLE) _(PARTICLEEMITTER) _(TEXTURE) _(USERMSG) _(CONVAR) _(IMESH) _(MATRIX) \ + _(SOUND) _(PIXELVISHANDLE) _(DLIGHT) _(VIDEO) _(FILE) _(LOCOMOTION) _(PATH) _(NAVAREA) \ + _(SOUNDHANDLE) _(NAVLADDER) _(PARTICLESYSTEM) _(PROJECTEDTEXTURE) _(PHYSCOLLIDE) _(COUNT) + +enum { + NONE = -1, +#define _TDEF(name) TYPE_##name, + GMODC_TYPES(_TDEF) +#undef _TDEF + LAST +}; + +#endif