diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..0b34454 --- /dev/null +++ b/.clang-format @@ -0,0 +1,32 @@ +BasedOnStyle: Google +ColumnLimit: 120 +IndentWidth: 4 +TabWidth: 4 +UseTab: Always +ReflowComments: false +AccessModifierOffset: -4 +IncludeBlocks: Preserve +BreakBeforeBraces: Allman +BreakBeforeTernaryOperators: true +BreakBeforeBinaryOperators: NonAssignment +SpaceInEmptyBlock: true +SpacesBeforeTrailingComments: 1 +SpaceAfterTemplateKeyword: true +IndentAccessModifiers: false +IndentRequiresClause: false +IndentCaseLabels: false +IndentPPDirectives: BeforeHash +InsertNewlineAtEOF: true +BinPackArguments: true +BinPackParameters: true +PackConstructorInitializers: BinPack +NamespaceIndentation: All +Cpp11BracedListStyle: false +FixNamespaceComments: false +AlignAfterOpenBracket: DontAlign +AlignOperands: false +AllowShortLoopsOnASingleLine: false +AllowShortBlocksOnASingleLine: Empty +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Never +AllowAllArgumentsOnNextLine: false diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..54de247 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,6 @@ +Checks: > + -* + clang-analyzer-* + +WarningsAsErrors: "*" +FormatStyle: file diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..6133a26 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +charset = utf-8 +indent_style = tab +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 896a994..0ec6e4a 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -1,71 +1,71 @@ name: Linux on: - push: - branches: [master] - pull_request: - branches: [master] + push: + branches: [master] + pull_request: + branches: [master] jobs: - build: - runs-on: ubuntu-18.04 - steps: - - name: Checkout - uses: actions/checkout@v2 + build: + runs-on: ubuntu-18.04 + steps: + - name: Checkout + uses: actions/checkout@v2 - - name: Vcpkg - uses: lukka/run-vcpkg@v11 - with: - vcpkgGitCommitId: 4a600e9fea71bd7872080cbb716797e04d30e6d3 + - name: Vcpkg + uses: lukka/run-vcpkg@v11 + with: + vcpkgGitCommitId: 4a600e9fea71bd7872080cbb716797e04d30e6d3 - - name: NASM - uses: ilammy/setup-nasm@v1 + - name: NASM + uses: ilammy/setup-nasm@v1 - - name: Dependencies - run: | - sudo apt-get install g++-multilib gcc-multilib - sudo dpkg --add-architecture i386 - sudo apt-get install nasm:i386 paxctl:i386 libtommath-dev:i386 + - name: Dependencies + run: | + sudo apt-get install g++-multilib gcc-multilib + sudo dpkg --add-architecture i386 + sudo apt-get install nasm:i386 paxctl:i386 libtommath-dev:i386 - - name: GCC - uses: egor-tensin/setup-gcc@v1 - with: - version: 9 - platform: x86 + - name: GCC + uses: egor-tensin/setup-gcc@v1 + with: + version: 9 + platform: x86 - - name: Plugin Interface - run: | - cd .. - curl -o plugin.zip https://iswenzz.com/github/gsclib/plugin.zip - 7z x plugin.zip + - name: Plugin Interface + run: | + cd .. + curl -o plugin.zip https://iswenzz.com/github/gsclib/plugin.zip + 7z x plugin.zip - - name: Build - run: | - mkdir build && cd build - cmake .. -DCMAKE_TOOLCHAIN_FILE=".vcpkg/linux.cmake" -DBUILD_TESTING=True - cmake --build . + - name: Build + run: | + mkdir build && cd build + cmake .. --preset linux -DBUILD_TESTING=True + cmake --build . - - name: Artifact - uses: actions/upload-artifact@v2 - with: - name: build-artifact - path: build + - name: Artifact + uses: actions/upload-artifact@v2 + with: + name: build-artifact + path: build - tests: - runs-on: ubuntu-18.04 - needs: [build] - steps: - - name: Checkout - uses: actions/checkout@v2 + tests: + runs-on: ubuntu-18.04 + needs: [build] + steps: + - name: Checkout + uses: actions/checkout@v2 - - name: Artifact - uses: actions/download-artifact@v2 - with: - name: build-artifact - path: build + - name: Artifact + uses: actions/download-artifact@v2 + with: + name: build-artifact + path: build - - name: Tests - working-directory: build - run: | - chmod +x bin/gsclib.Tests - ctest -C Release + - name: Tests + working-directory: build + run: | + chmod +x bin/gsclib.Tests + ctest -C Release diff --git a/CMakeLists.txt b/CMakeLists.txt index 13bb565..a6fff5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ set(CMAKE_STATIC_LIBRARY_PREFIX "") # CMake add_definitions(-D_CRT_SECURE_NO_WARNINGS -DWIN32_LEAN_AND_MEAN) set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +include(ClangTools) # CPack set(CPACK_PROJECT_NAME ${PROJECT_NAME}) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..c5bf940 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,23 @@ +{ + "version": 7, + "cmakeMinimumRequired": { + "major": 3, + "minor": 27, + "patch": 0 + }, + "configurePresets": [ + { + "name": "windows", + "generator": "MinGW Makefiles", + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": ".vcpkg/windows.cmake" + } + }, + { + "name": "linux", + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": ".vcpkg/linux.cmake" + } + } + ] +} diff --git a/README.md b/README.md index e85106f..3e656ba 100644 --- a/README.md +++ b/README.md @@ -4,27 +4,29 @@ [![CodeFactor](https://img.shields.io/codefactor/grade/github/Iswenzz/gsclib?label=codefactor&logo=codefactor)](https://www.codefactor.io/repository/github/iswenzz/gsclib) [![License](https://img.shields.io/github/license/Iswenzz/gsclib?color=blue&logo=gitbook&logoColor=white)](https://github.com/Iswenzz/gsclib/blob/master/LICENSE) -``gsclib`` acts as a standard library extension for the Call of Duty 4 scripting language. The features this library provides consists of an FTP/FTPS/SFTP client, an HTTP/HTTPS client, Regular Expression (PCRE2) support, Language Integrated Query (Linq) support, a MySQL connector for databases, casting/type conversion/fmt and other type utilities, ZIP files, async workers, and much more. More detailed information on each feature can be found in the documentation section. +`gsclib` acts as a standard library extension for the Call of Duty 4 scripting language. The features this library provides consists of an FTP/FTPS/SFTP client, an HTTP/HTTPS client, Regular Expression (PCRE2) support, Language Integrated Query (Linq) support, a MySQL connector for databases, casting/type conversion/fmt and other type utilities, ZIP files, async workers, and much more. More detailed information on each feature can be found in the documentation section. ## Features & Documentation -* [HTTP/HTTPS Client](https://github.com/Iswenzz/gsclib/blob/master/docs/http.md) -* [FTP/FTPS/SFTP Client](https://github.com/Iswenzz/gsclib/blob/master/docs/ftp.md) -* [Regular Expression (PCRE2)](https://github.com/Iswenzz/gsclib/blob/master/docs/regex.md) -* [Language Integrated Query (Linq)](https://github.com/Iswenzz/gsclib/blob/master/docs/linq.md) -* [MySQL](https://github.com/Iswenzz/gsclib/blob/master/docs/mysql.md) -* [Critical Sections](https://github.com/Iswenzz/gsclib/blob/master/docs/critical.md) -* [Utilities](https://github.com/Iswenzz/gsclib/blob/master/docs/utility.md) -* [File](https://github.com/Iswenzz/gsclib/blob/master/docs/file.md) -* [System](https://github.com/Iswenzz/gsclib/blob/master/docs/system.md) -* [Zip](https://github.com/Iswenzz/gsclib/blob/master/docs/zip.md) -* [Player](https://github.com/Iswenzz/gsclib/blob/master/docs/player.md) -* [Math](https://github.com/Iswenzz/gsclib/blob/master/docs/math.md) + +- [HTTP/HTTPS Client](https://github.com/Iswenzz/gsclib/blob/master/docs/http.md) +- [FTP/FTPS/SFTP Client](https://github.com/Iswenzz/gsclib/blob/master/docs/ftp.md) +- [Regular Expression (PCRE2)](https://github.com/Iswenzz/gsclib/blob/master/docs/regex.md) +- [Language Integrated Query (Linq)](https://github.com/Iswenzz/gsclib/blob/master/docs/linq.md) +- [MySQL](https://github.com/Iswenzz/gsclib/blob/master/docs/mysql.md) +- [Critical Sections](https://github.com/Iswenzz/gsclib/blob/master/docs/critical.md) +- [Utilities](https://github.com/Iswenzz/gsclib/blob/master/docs/utility.md) +- [File](https://github.com/Iswenzz/gsclib/blob/master/docs/file.md) +- [System](https://github.com/Iswenzz/gsclib/blob/master/docs/system.md) +- [Zip](https://github.com/Iswenzz/gsclib/blob/master/docs/zip.md) +- [Player](https://github.com/Iswenzz/gsclib/blob/master/docs/player.md) +- [Math](https://github.com/Iswenzz/gsclib/blob/master/docs/math.md) ## Instructions -In order to use this library, you'll need to compile the binary and place it to the CoD4 ``plugins`` directory. -Then you can simply use ``loadplugin gsclib`` in your ``server.cfg`` or as CLI arguments. -To initialize gsclib library you need to call ``GSCLIB_Init()`` at the start of your mod entry point. +In order to use this library, you'll need to compile the binary and place it to the CoD4 `plugins` directory. +Then you can simply use `loadplugin gsclib` in your `server.cfg` or as CLI arguments. + +To initialize gsclib library you need to call `GSCLIB_Init()` at the start of your mod entry point. ```c main() @@ -34,37 +36,45 @@ main() ``` ## Server + 1. Edit plugin_handler.h then recompile the server with a clean obj directory: + ```c #define MAX_SCRIPTFUNCTIONS 256 ``` ## Building (Linux) + _Pre-Requisites:_ + 1. [CGSC](https://github.com/Iswenzz/CGSC) and it's pre-requisites. 2. [CMake](https://cmake.org/) and [vcpkg](https://vcpkg.io/en/). _Build Command:_ - mkdir build && cd build - cmake .. -DCMAKE_TOOLCHAIN_FILE=.vcpkg/linux.cmake - cmake --build . + mkdir build && cd build + cmake .. --preset linux + cmake --build . ## Building (Windows) + _Pre-Requisites:_ + 1. [CGSC](https://github.com/Iswenzz/CGSC) and it's pre-requisites. 2. [CMake](https://cmake.org/) and [vcpkg](https://vcpkg.io/en/). _Build Command:_ - mkdir build && cd build - cmake .. -G "MinGW Makefiles" -DCMAKE_TOOLCHAIN_FILE=.vcpkg/windows.cmake - cmake --build . + mkdir build && cd build + cmake .. --preset windows + cmake --build . ## [Download](https://github.com/Iswenzz/gsclib/releases) ## Troubleshouting + For resolving missing dependencies you can use the [ldd](https://man7.org/linux/man-pages/man1/ldd.1.html) command for Linux, and [Dependency Walker](https://www.dependencywalker.com/) for Windows. ## Contributors: -***Note:*** If you would like to contribute to this repository, feel free to send a pull request, and I will review your code. Also feel free to post about any problems that may arise in the issues section of the repository. + +**_Note:_** If you would like to contribute to this repository, feel free to send a pull request, and I will review your code. Also feel free to post about any problems that may arise in the issues section of the repository. diff --git a/cmake/ClangTools.cmake b/cmake/ClangTools.cmake new file mode 100644 index 0000000..1bd646b --- /dev/null +++ b/cmake/ClangTools.cmake @@ -0,0 +1,12 @@ +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +add_custom_target(clang-tidy + COMMAND find . -type f \( -name '*.c' -o -name '*.h' \) -not -path './build/*' -exec clang-tidy --config-file=.clang-tidy {} + + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + +add_custom_target(clang-format + COMMAND find . -type f \( -name '*.c' -o -name '*.h' \) -not -path './build/*' -exec clang-format -style=file -i --verbose {} + + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + +set_target_properties(clang-tidy PROPERTIES FOLDER Clang) +set_target_properties(clang-format PROPERTIES FOLDER Clang) diff --git a/src/__test__/main.test.c b/src/__test__/main.test.c index a41735d..fe65d25 100644 --- a/src/__test__/main.test.c +++ b/src/__test__/main.test.c @@ -1,17 +1,17 @@ -#include -GREATEST_MAIN_DEFS(); - -extern SUITE(Suite_data_regex); -extern SUITE(Suite_data_zip); -extern SUITE(Suite_utils_vsnprintf); - -int main(int argc, char** argv) -{ - GREATEST_MAIN_BEGIN(); - - RUN_SUITE(Suite_data_regex); - RUN_SUITE(Suite_data_zip); - RUN_SUITE(Suite_utils_vsnprintf); - - GREATEST_MAIN_END(); -} +#include +GREATEST_MAIN_DEFS(); + +extern SUITE(Suite_data_regex); +extern SUITE(Suite_data_zip); +extern SUITE(Suite_utils_vsnprintf); + +int main(int argc, char** argv) +{ + GREATEST_MAIN_BEGIN(); + + RUN_SUITE(Suite_data_regex); + RUN_SUITE(Suite_data_zip); + RUN_SUITE(Suite_utils_vsnprintf); + + GREATEST_MAIN_END(); +} diff --git a/src/__test__/mock.c b/src/__test__/mock.c index cea5d82..dd131ad 100644 --- a/src/__test__/mock.c +++ b/src/__test__/mock.c @@ -1,174 +1,124 @@ #include -#include -#include -#include #include +#include +#include +#include void Plugin_Printf(const char* fmt, ...) { - va_list argptr; - va_start(argptr, fmt); - printf(fmt, argptr); - va_end(argptr); + va_list argptr; + va_start(argptr, fmt); + printf(fmt, argptr); + va_end(argptr); } void Plugin_Scr_Error(const char* msg) { - printf("%s\n", msg); + printf("%s\n", msg); } async_handler* Plugin_AsyncInit() { - return NULL; + return NULL; } -void Plugin_AsyncShutdown(async_handler* handler) -{ +void Plugin_AsyncShutdown(async_handler* handler) { } -} - -async_worker* Plugin_AsyncWorker(async_handler* handler, void* data, uv_work_cb callback, uv_after_work_cb afterCallback) +async_worker* Plugin_AsyncWorker(async_handler* handler, void* data, uv_work_cb callback, + uv_after_work_cb afterCallback) { - return NULL; + return NULL; } -void Plugin_AsyncWorkerDone(uv_work_t* req, async_status status) -{ - -} +void Plugin_AsyncWorkerDone(uv_work_t* req, async_status status) { } qboolean Plugin_CGSC_UnsupportedMessage(qboolean versionCondition, char* format, ...) { - return qfalse; + return qfalse; } float Plugin_CGSC_Version() { - return 0.0f; + return 0.0f; } client_t* Plugin_GetClientForClientNum(int clientnum) { - return NULL; + return NULL; } gentity_t* Plugin_GetGentityForEntityNum(int entnum) { - return NULL; + return NULL; } int Plugin_Milliseconds() { - return 0; + return 0; } const char* Plugin_NET_AdrToStringShortMT(netadr_t* a, char* buf, int len) { - return NULL; + return NULL; } const char* Plugin_SL_ConvertToString(int index) { - return NULL; + return NULL; } -void Plugin_Scr_AddVariable(VariableValue var) -{ +void Plugin_Scr_AddVariable(VariableValue var) { } -} +void Plugin_Scr_AddVector(vec3_t vec) { } -void Plugin_Scr_AddVector(vec3_t vec) -{ +void Plugin_Scr_AddArray() { } -} +void Plugin_Scr_AddArrayStringIndexed(int strIdx) { } -void Plugin_Scr_AddArray() -{ +void Plugin_Scr_AddBool(qboolean value) { } -} +void Plugin_Scr_AddFloat(float value) { } -void Plugin_Scr_AddArrayStringIndexed(int strIdx) -{ +void Plugin_Scr_AddInt(int value) { } -} +void Plugin_Scr_AddString(const char* string) { } -void Plugin_Scr_AddBool(qboolean value) -{ - -} - -void Plugin_Scr_AddFloat(float value) -{ - -} - -void Plugin_Scr_AddInt(int value) -{ - -} - -void Plugin_Scr_AddString(const char* string) -{ - -} - -void Plugin_Scr_AddUndefined() -{ - -} +void Plugin_Scr_AddUndefined() { } int Plugin_Scr_AllocString(const char* string) { - return 0; -} - -void Plugin_Scr_CallFunction(void (*function)(void), ...) -{ - + return 0; } -void Plugin_Scr_CallMethod(void (*function)(scr_entref_t), scr_entref_t ent, ...) -{ +void Plugin_Scr_CallFunction(void (*function)(void), ...) { } -} +void Plugin_Scr_CallMethod(void (*function)(scr_entref_t), scr_entref_t ent, ...) { } short Plugin_Scr_ExecThread(int callbackHook, unsigned int numArgs) { - return 0; + return 0; } -void Plugin_Scr_FreeThread(short threadId) -{ - -} +void Plugin_Scr_FreeThread(short threadId) { } int Plugin_Scr_GetThreadReturn() { - return 0; -} - -void Plugin_Scr_MakeArray() -{ - + return 0; } -void Plugin_Scr_ObjectError(const char* string) -{ - -} +void Plugin_Scr_MakeArray() { } -void Plugin_Scr_ParamError(int paramnum, const char* string) -{ +void Plugin_Scr_ObjectError(const char* string) { } -} +void Plugin_Scr_ParamError(int paramnum, const char* string) { } VariableValueArray Plugin_Scr_CreateArray(int length) { - VariableValueArray array; - array.length = length; - array.items = (VariableValue*)malloc(array.length * sizeof(VariableValue)); - return array; + VariableValueArray array; + array.length = length; + array.items = (VariableValue*)malloc(array.length * sizeof(VariableValue)); + return array; } void Plugin_Scr_FreeArray(VariableValueArray* array) @@ -178,69 +128,69 @@ void Plugin_Scr_FreeArray(VariableValueArray* array) VariableValueArray Plugin_Scr_GetArray(unsigned int paramnum) { - VariableValueArray array = { 0 }; - return array; + VariableValueArray array = { 0 }; + return array; } uint32_t Plugin_Scr_GetArrayFlags(VariableValueArray array) { - return 0; + return 0; } float Plugin_Scr_GetFloat(unsigned int paramnum) { - return 0.0f; + return 0.0f; } int Plugin_Scr_GetFunction(unsigned int paramnum) { - return 0; + return 0; } int Plugin_Scr_GetInt(unsigned int paramnum) { - return 0; + return 0; } int Plugin_Scr_GetNumParam() { - return 0; + return 0; } unsigned int Plugin_Scr_GetObjectType(unsigned int id) { - return 0; + return 0; } char* Plugin_Scr_GetString(unsigned int paramnum) { - return ""; + return ""; } VariableValue* Plugin_Scr_SelectParamOrDefault(unsigned int paramnum) { - return NULL; + return NULL; } VariableValue* Plugin_Scr_SelectParam(unsigned int paramnum) { - return NULL; + return NULL; } VariableValue* Plugin_Scr_GetTop(unsigned int paramnum) { - return NULL; + return NULL; } VariableValue Plugin_Scr_ReturnResult() { - VariableValue value = { 0 }; - return value; + VariableValue value = { 0 }; + return value; } short Plugin_Scr_ExecThreadResult(int callbackHook, unsigned int numArgs) { - return 0; + return 0; } char* Plugin_Cmd_Argv(int arg) @@ -250,15 +200,15 @@ char* Plugin_Cmd_Argv(int arg) int Plugin_Cmd_Argc() { - return 0; + return 0; } char* Plugin_Cmd_Args(char* buff, int bufsize) { - return NULL; + return NULL; } float Sys_GetCommonVersion() { - return 0.0f; + return 0.0f; } diff --git a/src/data/__test__/regex.test.c b/src/data/__test__/regex.test.c index 2734027..3a0d8d6 100644 --- a/src/data/__test__/regex.test.c +++ b/src/data/__test__/regex.test.c @@ -1,109 +1,69 @@ -#include "data/regex.h" -#include - -typedef struct -{ - char regex[256]; - char subject[MAX_STRING_CHARS]; - char* values[MAX_STRING_CHARS]; -} EXPECT_PCRE2; - -TEST test_regexMatch() -{ - EXPECT_PCRE2 expects[3] = { - { - "\\d+", - "hello123world456yes789", - { "123", "456", "789" } - }, - { - "\\d+", - "123world456yes789", - { "123", "456", "789" } - }, - { - "^([a-z0-9\\+_\\-]+)(\\.[a-z0-9\\+_\\-]+)*@([a-z0-9\\-]+\\.)+[a-z]{2,6}$", - "suxlolz1528@gmail.com", - { "suxlolz1528@gmail.com" } - } - }; - - PCRE2_VALUES* matches = NULL; - for (int i = 0; i < 3; i++) - { - matches = PCRE2_Match((PCRE2_SPTR)expects[i].subject, (PCRE2_SPTR)expects[i].regex); - for (int j = 0; matches != NULL && j < matches->count; j++) - ASSERT_STR_EQ(matches->results[j].string, expects[i].values[j]); - PCRE2_FreeValues(matches); - } - PASS(); -} - -TEST test_regexSplit() -{ - EXPECT_PCRE2 expects[3] = { - { - "\\d+", - "hello123world456yes789", - { "hello", "world", "yes" } - }, - { - "\\d+", - "123world456yes789", - { "world", "yes" } - }, - { - "^([a-z0-9\\+_\\-]+)(\\.[a-z0-9\\+_\\-]+)*@([a-z0-9\\-]+\\.)+[a-z]{2,6}$", - "suxlolz1528@gmail.com", - { 0 } - } - }; - - PCRE2_VALUES* splits = NULL; - for (int i = 0; i < 3; i++) - { - splits = PCRE2_Split((PCRE2_SPTR)expects[i].subject, (PCRE2_SPTR)expects[i].regex); - for (int j = 0; splits != NULL && j < splits->count; j++) - ASSERT_STR_EQ(splits->results[j].string, expects[i].values[j]); - PCRE2_FreeValues(splits); - } - PASS(); -} - -TEST test_regexReplace() -{ - EXPECT_PCRE2 expects[3] = { - { - "\\d+", - "hello123world456yes789", - { "hello_world_yes_"} - }, - { - "\\d+", - "123world456yes789", - { "_world_yes_" } - }, - { - "^([a-z0-9\\+_\\-]+)(\\.[a-z0-9\\+_\\-]+)*@([a-z0-9\\-]+\\.)+[a-z]{2,6}$", - "suxlolz1528@gmail.com", - { "_" } - } - }; - const char* replace = "_"; - char* string = NULL; - - for (int i = 0; i < 3; i++) - { - string = PCRE2_Replace((PCRE2_SPTR)expects[i].subject, (PCRE2_SPTR)expects[i].regex, replace); - ASSERT_STR_EQ(string, expects[i].values[0]); - free(string); - } - PASS(); -} - -SUITE(Suite_data_regex) -{ - RUN_TEST(test_regexMatch); - RUN_TEST(test_regexSplit); - RUN_TEST(test_regexReplace); -} +#include "data/regex.h" +#include + +typedef struct +{ + char regex[256]; + char subject[MAX_STRING_CHARS]; + char* values[MAX_STRING_CHARS]; +} EXPECT_PCRE2; + +TEST test_regexMatch() +{ + EXPECT_PCRE2 expects[3] = { { "\\d+", "hello123world456yes789", { "123", "456", "789" } }, + { "\\d+", "123world456yes789", { "123", "456", "789" } }, + { "^([a-z0-9\\+_\\-]+)(\\.[a-z0-9\\+_\\-]+)*@([a-z0-9\\-]+\\.)+[a-z]{2,6}$", "suxlolz1528@gmail.com", + { "suxlolz1528@gmail.com" } } }; + + PCRE2_VALUES* matches = NULL; + for (int i = 0; i < 3; i++) + { + matches = PCRE2_Match((PCRE2_SPTR)expects[i].subject, (PCRE2_SPTR)expects[i].regex); + for (int j = 0; matches != NULL && j < matches->count; j++) + ASSERT_STR_EQ(matches->results[j].string, expects[i].values[j]); + PCRE2_FreeValues(matches); + } + PASS(); +} + +TEST test_regexSplit() +{ + EXPECT_PCRE2 expects[3] = { { "\\d+", "hello123world456yes789", { "hello", "world", "yes" } }, + { "\\d+", "123world456yes789", { "world", "yes" } }, + { "^([a-z0-9\\+_\\-]+)(\\.[a-z0-9\\+_\\-]+)*@([a-z0-9\\-]+\\.)+[a-z]{2,6}$", "suxlolz1528@gmail.com", { 0 } } }; + + PCRE2_VALUES* splits = NULL; + for (int i = 0; i < 3; i++) + { + splits = PCRE2_Split((PCRE2_SPTR)expects[i].subject, (PCRE2_SPTR)expects[i].regex); + for (int j = 0; splits != NULL && j < splits->count; j++) + ASSERT_STR_EQ(splits->results[j].string, expects[i].values[j]); + PCRE2_FreeValues(splits); + } + PASS(); +} + +TEST test_regexReplace() +{ + EXPECT_PCRE2 expects[3] = { { "\\d+", "hello123world456yes789", { "hello_world_yes_" } }, + { "\\d+", "123world456yes789", { "_world_yes_" } }, + { "^([a-z0-9\\+_\\-]+)(\\.[a-z0-9\\+_\\-]+)*@([a-z0-9\\-]+\\.)+[a-z]{2,6}$", "suxlolz1528@gmail.com", + { "_" } } }; + const char* replace = "_"; + char* string = NULL; + + for (int i = 0; i < 3; i++) + { + string = PCRE2_Replace((PCRE2_SPTR)expects[i].subject, (PCRE2_SPTR)expects[i].regex, replace); + ASSERT_STR_EQ(string, expects[i].values[0]); + free(string); + } + PASS(); +} + +SUITE(Suite_data_regex) +{ + RUN_TEST(test_regexMatch); + RUN_TEST(test_regexSplit); + RUN_TEST(test_regexReplace); +} diff --git a/src/data/file.c b/src/data/file.c index 5795529..11ebc61 100644 --- a/src/data/file.c +++ b/src/data/file.c @@ -1,291 +1,292 @@ -#include "file.h" -#include "utils/vsnprintf.h" - -#include -#include - -void GScr_FILE_Create() -{ - CHECK_PARAMS(1, "Usage: FILE_Create()"); - - const char* path = Plugin_Scr_GetString(0); - - FILE* file = fopen(path, "w"); - Plugin_Scr_AddBool(file ? fclose(file) == 0 : qfalse); -} - -void GScr_FILE_Open() -{ - CHECK_PARAMS(2, "Usage: FILE_Open(, )"); - - const char* path = Plugin_Scr_GetString(0); - const char* mode = Plugin_Scr_GetString(1); - - FILE* file = fopen(path, mode); - if (!file) - { - Plugin_Scr_Error(fmt("Error: Couldn't open file %s", path)); - return; - } - Plugin_Scr_AddInt((int)file); -} - -void GScr_FILE_Exists() -{ - CHECK_PARAMS(1, "Usage: FILE_Exists()"); - - struct stat fileinfo; - const char* path = Plugin_Scr_GetString(0); - - Plugin_Scr_AddBool(stat(path, &fileinfo) == 0); -} - -void GScr_FILE_ReadLine() -{ - CHECK_PARAMS(1, "Usage: FILE_ReadLine()"); - - char buffer[MAX_STRING_CHARS] = { 0 }; - FILE* file = (FILE*)Plugin_Scr_GetInt(0); - - if (!file) - { - Plugin_Scr_Error("Error: File handle is NULL"); - return; - } - fgets(buffer, sizeof(buffer), file); - buffer[strcspn(buffer, "\n")] = 0; - Plugin_Scr_AddString(buffer); -} - -void GScr_FILE_WriteLine() -{ - const int argCount = Plugin_Scr_GetNumParam(); - if (argCount < 2) - { - Plugin_Scr_Error("Usage: FILE_Write(, , )"); - return; - } - char buffer[MAX_STRING_CHARS] = { 0 }; - FILE* file = (FILE*)Plugin_Scr_GetInt(0); - const char* format = Plugin_Scr_GetString(1); - - if (!file) - { - Plugin_Scr_AddBool(qfalse); - return; - } - if (argCount > 2) - { - VariableValueArray args = Plugin_Scr_CreateArray(argCount - 2); - - for (int i = 2; i < argCount; i++) - args.items[i - 2] = *Plugin_Scr_SelectParam(i); - Scr_vsnprintf(buffer, sizeof(buffer), format, args); - Plugin_Scr_FreeArray(&args); - } - else - strcpy(buffer, format); - - int code = fprintf(file, "%s\n", buffer); - fflush(file); - Plugin_Scr_AddBool(code != EOF); -} - -void GScr_FILE_ReadLines() -{ - CHECK_PARAMS(1, "Usage: FILE_ReadLines()"); - - char buffer[MAX_STRING_CHARS] = { 0 }; - FILE* file = (FILE*)Plugin_Scr_GetInt(0); - - if (!file) - { - Plugin_Scr_Error("Error: File handle is NULL"); - return; - } - - Plugin_Scr_MakeArray(); - while (fgets(buffer, sizeof(buffer), file)) - { - buffer[strcspn(buffer, "\n")] = 0; - Plugin_Scr_AddString(buffer); - Plugin_Scr_AddArray(); - } -} - -void GScr_FILE_WriteLines() -{ - CHECK_PARAMS(2, "Usage: FILE_WriteLines(, )"); - - FILE* file = (FILE*)Plugin_Scr_GetInt(0); - VariableValueArray array = Plugin_Scr_GetArray(1); - int lines = 0; - - for (int i = 0; i < array.length; i++) - { - if (array.items[i].type == VAR_STRING) - { - fprintf(file, "%s\n", Plugin_SL_ConvertToString(array.items[i].u.stringValue)); - lines++; - } - } - Plugin_Scr_AddInt(lines); - Plugin_Scr_FreeArray(&array); -} - -void GScr_FILE_Seek() -{ - CHECK_PARAMS(2, "Usage: FILE_Seek(, )"); - - FILE* file = (FILE*)Plugin_Scr_GetInt(0); - int offset = Plugin_Scr_GetInt(1); - - if (!file) - { - Plugin_Scr_Error("Error: File handle is NULL"); - return; - } - Plugin_Scr_AddBool(fseek(file, offset, SEEK_SET) == 0); -} - -void GScr_FILE_Read() -{ - CHECK_PARAMS(1, "Usage: FILE_Read()"); - - char buffer[MAX_STRING_CHARS] = { 0 }; - FILE* file = (FILE*)Plugin_Scr_GetInt(0); - - if (!file) - { - Plugin_Scr_Error("Error: File handle is NULL"); - return; - } - fread(buffer, sizeof(buffer), 1, file); - Plugin_Scr_AddString(buffer); -} - -void GScr_FILE_Write() -{ - const int argCount = Plugin_Scr_GetNumParam(); - if (argCount < 2) - { - Plugin_Scr_Error("Usage: FILE_Write(, , )"); - return; - } - char buffer[MAX_STRING_CHARS] = { 0 }; - FILE* file = (FILE*)Plugin_Scr_GetInt(0); - const char* format = Plugin_Scr_GetString(1); - - if (!file) - { - Plugin_Scr_AddBool(qfalse); - return; - } - if (argCount > 2) - { - VariableValueArray args; - args.length = argCount - 2; - args.items = (VariableValue*)malloc(args.length * sizeof(VariableValue)); - - for (int i = 2; i < argCount; i++) - args.items[i - 2] = *Plugin_Scr_SelectParam(i); - Scr_vsnprintf(buffer, sizeof(buffer), format, args); - Plugin_Scr_FreeArray(&args); - } - else - strcpy(buffer, format); - - int code = fputs(buffer, file); - fflush(file); - Plugin_Scr_AddBool(code != EOF); -} - -void GScr_FILE_Delete() -{ - CHECK_PARAMS(1, "Usage: FILE_Delete()"); - - const char* path = Plugin_Scr_GetString(0); - Plugin_Scr_AddBool(remove(path) == 0); -} - -void GScr_FILE_Close() -{ - CHECK_PARAMS(1, "Usage: FILE_Close()"); - - FILE* file = (FILE*)Plugin_Scr_GetInt(0); - Plugin_Scr_AddBool(file ? fclose(file) == 0 : qfalse); -} - -void GScr_FILE_MkDir() -{ - CHECK_PARAMS(1, "Usage: FILE_MkDir()"); - const char* path = Plugin_Scr_GetString(0); - -#ifdef _WIN32 - Plugin_Scr_AddBool(CreateDirectory(path, NULL)); -#else - Plugin_Scr_AddBool(mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) == 0); -#endif -} - -void GScr_FILE_RmDir() -{ - CHECK_PARAMS(1, "Usage: FILE_RmDir()"); - const char* path = Plugin_Scr_GetString(0); - -#ifdef _WIN32 - Plugin_Scr_AddBool(WIN_RemoveDirectory(path) == 0); -#else - Plugin_Scr_AddBool(nftw(path, UNIX_RemoveDirectory, 64, FTW_DEPTH | FTW_PHYS) == 0); -#endif -} - -void GScr_FILE_ReadDir() -{ - CHECK_PARAMS(1, "Usage: FILE_ReadDir()"); - - const char* path = Plugin_Scr_GetString(0); - DIR* dir = opendir(path); - struct dirent* entry; - - if (!dir) - { - Plugin_Scr_Error(fmt("Error: Couldn't open dir %s", path)); - return; - } - - Plugin_Scr_MakeArray(); - while ((entry = readdir(dir)) != NULL) - { - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) - continue; - Plugin_Scr_AddString(entry->d_name); - Plugin_Scr_AddArray(); - } - closedir(dir); -} - -#ifdef _WIN32 -BOOL WIN_RemoveDirectory(const char* path) -{ - // Required to set 2 nulls at end of argument to SHFileOperation. - int len = strlen(path) + 2; - char* tempdir = (char*)malloc(len); - memset(tempdir, 0, len); - strcpy(tempdir, path); - - SHFILEOPSTRUCT file_op = { NULL, FO_DELETE, tempdir, NULL, - FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT, false, 0, "" }; - int ret = SHFileOperation(&file_op); - free(tempdir); - - return ret; -} -#else -int UNIX_RemoveDirectory(const char* path, const struct stat* sb, int typeflag, PFTW ftwbuf) -{ - int ret = remove(path); - if (ret) perror(path); - return ret; -} -#endif +#include "file.h" +#include "utils/vsnprintf.h" + +#include +#include + +void GScr_FILE_Create() +{ + CHECK_PARAMS(1, "Usage: FILE_Create()"); + + const char* path = Plugin_Scr_GetString(0); + + FILE* file = fopen(path, "w"); + Plugin_Scr_AddBool(file ? fclose(file) == 0 : qfalse); +} + +void GScr_FILE_Open() +{ + CHECK_PARAMS(2, "Usage: FILE_Open(, )"); + + const char* path = Plugin_Scr_GetString(0); + const char* mode = Plugin_Scr_GetString(1); + + FILE* file = fopen(path, mode); + if (!file) + { + Plugin_Scr_Error(fmt("Error: Couldn't open file %s", path)); + return; + } + Plugin_Scr_AddInt((int)file); +} + +void GScr_FILE_Exists() +{ + CHECK_PARAMS(1, "Usage: FILE_Exists()"); + + struct stat fileinfo; + const char* path = Plugin_Scr_GetString(0); + + Plugin_Scr_AddBool(stat(path, &fileinfo) == 0); +} + +void GScr_FILE_ReadLine() +{ + CHECK_PARAMS(1, "Usage: FILE_ReadLine()"); + + char buffer[MAX_STRING_CHARS] = { 0 }; + FILE* file = (FILE*)Plugin_Scr_GetInt(0); + + if (!file) + { + Plugin_Scr_Error("Error: File handle is NULL"); + return; + } + fgets(buffer, sizeof(buffer), file); + buffer[strcspn(buffer, "\n")] = 0; + Plugin_Scr_AddString(buffer); +} + +void GScr_FILE_WriteLine() +{ + const int argCount = Plugin_Scr_GetNumParam(); + if (argCount < 2) + { + Plugin_Scr_Error("Usage: FILE_Write(, , )"); + return; + } + char buffer[MAX_STRING_CHARS] = { 0 }; + FILE* file = (FILE*)Plugin_Scr_GetInt(0); + const char* format = Plugin_Scr_GetString(1); + + if (!file) + { + Plugin_Scr_AddBool(qfalse); + return; + } + if (argCount > 2) + { + VariableValueArray args = Plugin_Scr_CreateArray(argCount - 2); + + for (int i = 2; i < argCount; i++) + args.items[i - 2] = *Plugin_Scr_SelectParam(i); + Scr_vsnprintf(buffer, sizeof(buffer), format, args); + Plugin_Scr_FreeArray(&args); + } + else + strcpy(buffer, format); + + int code = fprintf(file, "%s\n", buffer); + fflush(file); + Plugin_Scr_AddBool(code != EOF); +} + +void GScr_FILE_ReadLines() +{ + CHECK_PARAMS(1, "Usage: FILE_ReadLines()"); + + char buffer[MAX_STRING_CHARS] = { 0 }; + FILE* file = (FILE*)Plugin_Scr_GetInt(0); + + if (!file) + { + Plugin_Scr_Error("Error: File handle is NULL"); + return; + } + + Plugin_Scr_MakeArray(); + while (fgets(buffer, sizeof(buffer), file)) + { + buffer[strcspn(buffer, "\n")] = 0; + Plugin_Scr_AddString(buffer); + Plugin_Scr_AddArray(); + } +} + +void GScr_FILE_WriteLines() +{ + CHECK_PARAMS(2, "Usage: FILE_WriteLines(, )"); + + FILE* file = (FILE*)Plugin_Scr_GetInt(0); + VariableValueArray array = Plugin_Scr_GetArray(1); + int lines = 0; + + for (int i = 0; i < array.length; i++) + { + if (array.items[i].type == VAR_STRING) + { + fprintf(file, "%s\n", Plugin_SL_ConvertToString(array.items[i].u.stringValue)); + lines++; + } + } + Plugin_Scr_AddInt(lines); + Plugin_Scr_FreeArray(&array); +} + +void GScr_FILE_Seek() +{ + CHECK_PARAMS(2, "Usage: FILE_Seek(, )"); + + FILE* file = (FILE*)Plugin_Scr_GetInt(0); + int offset = Plugin_Scr_GetInt(1); + + if (!file) + { + Plugin_Scr_Error("Error: File handle is NULL"); + return; + } + Plugin_Scr_AddBool(fseek(file, offset, SEEK_SET) == 0); +} + +void GScr_FILE_Read() +{ + CHECK_PARAMS(1, "Usage: FILE_Read()"); + + char buffer[MAX_STRING_CHARS] = { 0 }; + FILE* file = (FILE*)Plugin_Scr_GetInt(0); + + if (!file) + { + Plugin_Scr_Error("Error: File handle is NULL"); + return; + } + fread(buffer, sizeof(buffer), 1, file); + Plugin_Scr_AddString(buffer); +} + +void GScr_FILE_Write() +{ + const int argCount = Plugin_Scr_GetNumParam(); + if (argCount < 2) + { + Plugin_Scr_Error("Usage: FILE_Write(, , )"); + return; + } + char buffer[MAX_STRING_CHARS] = { 0 }; + FILE* file = (FILE*)Plugin_Scr_GetInt(0); + const char* format = Plugin_Scr_GetString(1); + + if (!file) + { + Plugin_Scr_AddBool(qfalse); + return; + } + if (argCount > 2) + { + VariableValueArray args; + args.length = argCount - 2; + args.items = (VariableValue*)malloc(args.length * sizeof(VariableValue)); + + for (int i = 2; i < argCount; i++) + args.items[i - 2] = *Plugin_Scr_SelectParam(i); + Scr_vsnprintf(buffer, sizeof(buffer), format, args); + Plugin_Scr_FreeArray(&args); + } + else + strcpy(buffer, format); + + int code = fputs(buffer, file); + fflush(file); + Plugin_Scr_AddBool(code != EOF); +} + +void GScr_FILE_Delete() +{ + CHECK_PARAMS(1, "Usage: FILE_Delete()"); + + const char* path = Plugin_Scr_GetString(0); + Plugin_Scr_AddBool(remove(path) == 0); +} + +void GScr_FILE_Close() +{ + CHECK_PARAMS(1, "Usage: FILE_Close()"); + + FILE* file = (FILE*)Plugin_Scr_GetInt(0); + Plugin_Scr_AddBool(file ? fclose(file) == 0 : qfalse); +} + +void GScr_FILE_MkDir() +{ + CHECK_PARAMS(1, "Usage: FILE_MkDir()"); + const char* path = Plugin_Scr_GetString(0); + +#ifdef _WIN32 + Plugin_Scr_AddBool(CreateDirectory(path, NULL)); +#else + Plugin_Scr_AddBool(mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) == 0); +#endif +} + +void GScr_FILE_RmDir() +{ + CHECK_PARAMS(1, "Usage: FILE_RmDir()"); + const char* path = Plugin_Scr_GetString(0); + +#ifdef _WIN32 + Plugin_Scr_AddBool(WIN_RemoveDirectory(path) == 0); +#else + Plugin_Scr_AddBool(nftw(path, UNIX_RemoveDirectory, 64, FTW_DEPTH | FTW_PHYS) == 0); +#endif +} + +void GScr_FILE_ReadDir() +{ + CHECK_PARAMS(1, "Usage: FILE_ReadDir()"); + + const char* path = Plugin_Scr_GetString(0); + DIR* dir = opendir(path); + struct dirent* entry; + + if (!dir) + { + Plugin_Scr_Error(fmt("Error: Couldn't open dir %s", path)); + return; + } + + Plugin_Scr_MakeArray(); + while ((entry = readdir(dir)) != NULL) + { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + Plugin_Scr_AddString(entry->d_name); + Plugin_Scr_AddArray(); + } + closedir(dir); +} + +#ifdef _WIN32 +BOOL WIN_RemoveDirectory(const char* path) +{ + // Required to set 2 nulls at end of argument to SHFileOperation. + int len = strlen(path) + 2; + char* tempdir = (char*)malloc(len); + memset(tempdir, 0, len); + strcpy(tempdir, path); + + SHFILEOPSTRUCT file_op = { NULL, FO_DELETE, tempdir, NULL, FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT, false, + 0, "" }; + int ret = SHFileOperation(&file_op); + free(tempdir); + + return ret; +} +#else +int UNIX_RemoveDirectory(const char* path, const struct stat* sb, int typeflag, PFTW ftwbuf) +{ + int ret = remove(path); + if (ret) + perror(path); + return ret; +} +#endif diff --git a/src/data/file.h b/src/data/file.h index 9af9e71..bce9698 100644 --- a/src/data/file.h +++ b/src/data/file.h @@ -4,8 +4,8 @@ #define _FILE_OFFSET_BITS 64 #define _XOPEN_SOURCE 700 -#include #include +#include #if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) @@ -21,7 +21,7 @@ #include #include - typedef struct FTW* PFTW; +typedef struct FTW* PFTW; #endif #ifndef MAX_PATH diff --git a/src/data/regex.c b/src/data/regex.c index a8a78a1..723eceb 100644 --- a/src/data/regex.c +++ b/src/data/regex.c @@ -1,294 +1,297 @@ -#include "regex.h" - -#include -#include -#include - -void GScr_RegexSplit() -{ - CHECK_PARAMS(2, "Usage: RegexSplit(, )"); - - const char* subject = Plugin_Scr_GetString(0); - const char* regex = Plugin_Scr_GetString(1); - - PCRE2_VALUES* splits = PCRE2_Split((PCRE2_SPTR)subject, (PCRE2_SPTR)regex); - if (splits == NULL) return; - - Plugin_Scr_MakeArray(); - for (int i = 0; i < splits->count; i++) - { - Plugin_Scr_AddString(splits->results[i].string); - Plugin_Scr_AddArray(); - } - PCRE2_FreeValues(splits); -} - -void GScr_RegexMatch() -{ - CHECK_PARAMS(2, "Usage: RegexMatch(, )"); - - const char* subject = Plugin_Scr_GetString(0); - const char* regex = Plugin_Scr_GetString(1); - - PCRE2_VALUES* matches = PCRE2_Match((PCRE2_SPTR)subject, (PCRE2_SPTR)regex); - if (matches == NULL) return; - - Plugin_Scr_MakeArray(); - for (int i = 0; i < matches->count; i++) - { - Plugin_Scr_AddString(matches->results[i].string); - Plugin_Scr_AddArray(); - } - PCRE2_FreeValues(matches); -} - -void GScr_RegexReplace() -{ - CHECK_PARAMS(3, "Usage: RegexReplace(, , )"); - - const char* subject = Plugin_Scr_GetString(0); - const char* replace = Plugin_Scr_GetString(1); - const char* regex = Plugin_Scr_GetString(2); - - char* string = PCRE2_Replace((PCRE2_SPTR)subject, (PCRE2_SPTR)regex, replace); - if (string == NULL) return; - - Plugin_Scr_AddString(string); - free(string); -} - -qboolean PCRE2_GetUTFOption(pcre2_code* re, uint32_t* optionBits) -{ - pcre2_pattern_info(re, PCRE2_INFO_ALLOPTIONS, optionBits); - return (*optionBits & PCRE2_UTF) != 0; -} - -qboolean PCRE2_IsNewlineCRLF(pcre2_code* re, uint32_t* newline) -{ - pcre2_pattern_info(re, PCRE2_INFO_NEWLINE, newline); - return *newline == PCRE2_NEWLINE_ANY || - *newline == PCRE2_NEWLINE_CRLF || - *newline == PCRE2_NEWLINE_ANYCRLF; -} - -qboolean PCRE2_HasMatches(int rc, pcre2_code* re, pcre2_match_data* matchData) -{ - if (rc < 0) - { - switch (rc) - { - case PCRE2_ERROR_NOMATCH: - break; - default: - Plugin_Scr_Error(fmt("Matching error %d\n", rc)); - break; - } - pcre2_match_data_free(matchData); - pcre2_code_free(re); - return qfalse; - } - return qtrue; -} - -qboolean PCRE2_CompileSuccess(pcre2_code* re, int* errorCode, PCRE2_SIZE* errorOffset) -{ - if (re != NULL) - return qtrue; - - PCRE2_UCHAR buffer[256]; - pcre2_get_error_message(*errorCode, buffer, sizeof(buffer)); - - Plugin_Scr_Error(fmt("PCRE2 compilation failed at offset %d: %s\n", *(int*)errorOffset, buffer)); - pcre2_code_free(re); - return qfalse; -} - -void PCRE2_AddValue(PCRE2_VALUE* value, char* string, int length, PCRE2_VALUES* values) -{ - if (values->results == NULL) - values->results = (PCRE2_VALUE*)calloc(1, sizeof(PCRE2_VALUE)); - else - { - PCRE2_VALUE* temp = (PCRE2_VALUE*)realloc(values->results, (values->count + 1) * sizeof(PCRE2_VALUE)); - if (temp != NULL) values->results = temp; - } - values->results[values->count] = *value; - strncpy(values->results[values->count].string, string, length); - values->results[values->count].string[length] = '\0'; - values->count++; -} - -PCRE2_VALUES* PCRE2_Compile(PCRE2_SPTR subject, PCRE2_SPTR regex) -{ - PCRE2_SIZE subjectLength = strlen((char *)subject); - PCRE2_SIZE errorOffset; - const int groupIndex = 0; // Capturing groups won't be part of the result values. - int errorCode; - int vectorMatchesCount = 0; - PCRE2_VECTOR vectors[subjectLength + 1]; - PCRE2_VALUES* values = (PCRE2_VALUES*)calloc(1, sizeof(PCRE2_VALUES)); - - pcre2_code* re = pcre2_compile(regex, PCRE2_ZERO_TERMINATED, 0, &errorCode, &errorOffset, NULL); - if (!PCRE2_CompileSuccess(re, &errorCode, &errorOffset)) - { - free(values); - return NULL; - } - - pcre2_match_data* matchData = pcre2_match_data_create_from_pattern(re, NULL); - int rc = pcre2_match(re, subject, subjectLength, 0, 0, matchData, NULL); - if (!PCRE2_HasMatches(rc, re, matchData)) - { - free(values); - return NULL; - } - - PCRE2_SIZE* ovector = pcre2_get_ovector_pointer(matchData); - vectors[vectorMatchesCount].position = subject + ovector[2 * groupIndex] - subject; - vectors[vectorMatchesCount].length = ovector[2 * groupIndex + 1] - ovector[2 * groupIndex]; - vectorMatchesCount++; - - uint32_t optionBits; - qboolean utf8 = PCRE2_GetUTFOption(re, &optionBits); - - uint32_t newline; - qboolean isNewlineCRLF = PCRE2_IsNewlineCRLF(re, &newline); - - // Find sub matches - for (;;) - { - uint32_t options = 0; - PCRE2_SIZE startOffset = ovector[1]; - - /* If the previous match was for an empty subject, we are finished if we are - at the end of the subject. Otherwise, arrange to run another match at the - same point to see if a non-empty match can be found. */ - - if (ovector[0] == ovector[1]) - { - if (ovector[0] == subjectLength) break; - options = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED; - } - - rc = pcre2_match(re, subject, subjectLength, startOffset, options, matchData, NULL); - if (rc == PCRE2_ERROR_NOMATCH) - { - if (options == 0) break; - ovector[1] = startOffset + 1; - - // If CRLF is a newline advance by one more character - if (isNewlineCRLF && startOffset < subjectLength - 1 && - subject[startOffset] == '\r' && subject[startOffset + 1] == '\n') - ovector[1] += 1; - else if (utf8) - { - // Otherwise, ensure we advance a whole UTF-8 character - while (ovector[1] < subjectLength) - { - if ((subject[ovector[1]] & 0xc0) != 0x80) break; - ovector[1] += 1; - } - } - continue; - } - if (!PCRE2_HasMatches(rc, re, matchData)) - break; - - vectors[vectorMatchesCount].position = subject + ovector[2 * groupIndex] - subject; - vectors[vectorMatchesCount].length = ovector[2 * groupIndex + 1] - ovector[2 * groupIndex]; - vectorMatchesCount++; - } - - // Build values - for (int i = 0; i < vectorMatchesCount; i++) - { - PCRE2_VALUE value = { 0 }; - PCRE2_VECTOR current = vectors[i]; - PCRE2_VECTOR last = vectors[i - 1]; - - // Check for unmatched string - if (current.position != 0) - { - if (!i) - { - int length = current.position; - value.matched = qfalse; - PCRE2_AddValue(&value, (char *)subject, length, values); - } - else if (i > 0) - { - int pos = last.position + last.length; - if (pos != current.position) - { - int length = current.position - pos; - value.matched = qfalse; - PCRE2_AddValue(&value, (char*)subject + pos, length, values); - } - } - } - - // Matched string - value.matched = qtrue; - PCRE2_AddValue(&value, (char*)subject + current.position, current.length, values); - } - pcre2_match_data_free(matchData); - pcre2_code_free(re); - - return values; -} - -void PCRE2_FreeValues(PCRE2_VALUES* values) -{ - if (values != NULL) - { - if (values->results != NULL) - free(values->results); - free(values); - } - values = NULL; -} - -PCRE2_VALUES* PCRE2_Match(PCRE2_SPTR subject, PCRE2_SPTR regex) -{ - PCRE2_VALUES* matches = (PCRE2_VALUES*)calloc(1, sizeof(PCRE2_VALUES)); - PCRE2_VALUES* values = PCRE2_Compile(subject, regex); - - for (int i = 0; i < values->count; i++) - { - if (values->results[i].matched) - { - PCRE2_AddValue(&values->results[i], values->results[i].string, - strlen(values->results[i].string), matches); - } - } - PCRE2_FreeValues(values); - return matches; -} - -PCRE2_VALUES* PCRE2_Split(PCRE2_SPTR subject, PCRE2_SPTR regex) -{ - PCRE2_VALUES* splits = (PCRE2_VALUES*)calloc(1, sizeof(PCRE2_VALUES)); - PCRE2_VALUES* values = PCRE2_Compile(subject, regex); - - for (int i = 0; i < values->count; i++) - { - if (!values->results[i].matched) - { - PCRE2_AddValue(&values->results[i], values->results[i].string, - strlen(values->results[i].string), splits); - } - } - PCRE2_FreeValues(values); - return splits; -} - -char* PCRE2_Replace(PCRE2_SPTR subject, PCRE2_SPTR regex, const char* replace) -{ - char* string = (char*)calloc(MAX_STRING_CHARS, sizeof(char)); - PCRE2_VALUES* values = PCRE2_Compile(subject, regex); - - for (int i = 0; i < values->count; i++) - strcat(string, !values->results[i].matched ? values->results[i].string : replace); - PCRE2_FreeValues(values); - return string; -} +#include "regex.h" + +#include +#include +#include + +void GScr_RegexSplit() +{ + CHECK_PARAMS(2, "Usage: RegexSplit(, )"); + + const char* subject = Plugin_Scr_GetString(0); + const char* regex = Plugin_Scr_GetString(1); + + PCRE2_VALUES* splits = PCRE2_Split((PCRE2_SPTR)subject, (PCRE2_SPTR)regex); + if (splits == NULL) + return; + + Plugin_Scr_MakeArray(); + for (int i = 0; i < splits->count; i++) + { + Plugin_Scr_AddString(splits->results[i].string); + Plugin_Scr_AddArray(); + } + PCRE2_FreeValues(splits); +} + +void GScr_RegexMatch() +{ + CHECK_PARAMS(2, "Usage: RegexMatch(, )"); + + const char* subject = Plugin_Scr_GetString(0); + const char* regex = Plugin_Scr_GetString(1); + + PCRE2_VALUES* matches = PCRE2_Match((PCRE2_SPTR)subject, (PCRE2_SPTR)regex); + if (matches == NULL) + return; + + Plugin_Scr_MakeArray(); + for (int i = 0; i < matches->count; i++) + { + Plugin_Scr_AddString(matches->results[i].string); + Plugin_Scr_AddArray(); + } + PCRE2_FreeValues(matches); +} + +void GScr_RegexReplace() +{ + CHECK_PARAMS(3, "Usage: RegexReplace(, , )"); + + const char* subject = Plugin_Scr_GetString(0); + const char* replace = Plugin_Scr_GetString(1); + const char* regex = Plugin_Scr_GetString(2); + + char* string = PCRE2_Replace((PCRE2_SPTR)subject, (PCRE2_SPTR)regex, replace); + if (string == NULL) + return; + + Plugin_Scr_AddString(string); + free(string); +} + +qboolean PCRE2_GetUTFOption(pcre2_code* re, uint32_t* optionBits) +{ + pcre2_pattern_info(re, PCRE2_INFO_ALLOPTIONS, optionBits); + return (*optionBits & PCRE2_UTF) != 0; +} + +qboolean PCRE2_IsNewlineCRLF(pcre2_code* re, uint32_t* newline) +{ + pcre2_pattern_info(re, PCRE2_INFO_NEWLINE, newline); + return *newline == PCRE2_NEWLINE_ANY || *newline == PCRE2_NEWLINE_CRLF || *newline == PCRE2_NEWLINE_ANYCRLF; +} + +qboolean PCRE2_HasMatches(int rc, pcre2_code* re, pcre2_match_data* matchData) +{ + if (rc < 0) + { + switch (rc) + { + case PCRE2_ERROR_NOMATCH: + break; + default: + Plugin_Scr_Error(fmt("Matching error %d\n", rc)); + break; + } + pcre2_match_data_free(matchData); + pcre2_code_free(re); + return qfalse; + } + return qtrue; +} + +qboolean PCRE2_CompileSuccess(pcre2_code* re, int* errorCode, PCRE2_SIZE* errorOffset) +{ + if (re != NULL) + return qtrue; + + PCRE2_UCHAR buffer[256]; + pcre2_get_error_message(*errorCode, buffer, sizeof(buffer)); + + Plugin_Scr_Error(fmt("PCRE2 compilation failed at offset %d: %s\n", *(int*)errorOffset, buffer)); + pcre2_code_free(re); + return qfalse; +} + +void PCRE2_AddValue(PCRE2_VALUE* value, char* string, int length, PCRE2_VALUES* values) +{ + if (values->results == NULL) + values->results = (PCRE2_VALUE*)calloc(1, sizeof(PCRE2_VALUE)); + else + { + PCRE2_VALUE* temp = (PCRE2_VALUE*)realloc(values->results, (values->count + 1) * sizeof(PCRE2_VALUE)); + if (temp != NULL) + values->results = temp; + } + values->results[values->count] = *value; + strncpy(values->results[values->count].string, string, length); + values->results[values->count].string[length] = '\0'; + values->count++; +} + +PCRE2_VALUES* PCRE2_Compile(PCRE2_SPTR subject, PCRE2_SPTR regex) +{ + PCRE2_SIZE subjectLength = strlen((char*)subject); + PCRE2_SIZE errorOffset; + const int groupIndex = 0; // Capturing groups won't be part of the result values. + int errorCode; + int vectorMatchesCount = 0; + PCRE2_VECTOR vectors[subjectLength + 1]; + PCRE2_VALUES* values = (PCRE2_VALUES*)calloc(1, sizeof(PCRE2_VALUES)); + + pcre2_code* re = pcre2_compile(regex, PCRE2_ZERO_TERMINATED, 0, &errorCode, &errorOffset, NULL); + if (!PCRE2_CompileSuccess(re, &errorCode, &errorOffset)) + { + free(values); + return NULL; + } + + pcre2_match_data* matchData = pcre2_match_data_create_from_pattern(re, NULL); + int rc = pcre2_match(re, subject, subjectLength, 0, 0, matchData, NULL); + if (!PCRE2_HasMatches(rc, re, matchData)) + { + free(values); + return NULL; + } + + PCRE2_SIZE* ovector = pcre2_get_ovector_pointer(matchData); + vectors[vectorMatchesCount].position = subject + ovector[2 * groupIndex] - subject; + vectors[vectorMatchesCount].length = ovector[2 * groupIndex + 1] - ovector[2 * groupIndex]; + vectorMatchesCount++; + + uint32_t optionBits; + qboolean utf8 = PCRE2_GetUTFOption(re, &optionBits); + + uint32_t newline; + qboolean isNewlineCRLF = PCRE2_IsNewlineCRLF(re, &newline); + + // Find sub matches + for (;;) + { + uint32_t options = 0; + PCRE2_SIZE startOffset = ovector[1]; + + /* If the previous match was for an empty subject, we are finished if we are + at the end of the subject. Otherwise, arrange to run another match at the + same point to see if a non-empty match can be found. */ + + if (ovector[0] == ovector[1]) + { + if (ovector[0] == subjectLength) + break; + options = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED; + } + + rc = pcre2_match(re, subject, subjectLength, startOffset, options, matchData, NULL); + if (rc == PCRE2_ERROR_NOMATCH) + { + if (options == 0) + break; + ovector[1] = startOffset + 1; + + // If CRLF is a newline advance by one more character + if (isNewlineCRLF && startOffset < subjectLength - 1 && subject[startOffset] == '\r' + && subject[startOffset + 1] == '\n') + ovector[1] += 1; + else if (utf8) + { + // Otherwise, ensure we advance a whole UTF-8 character + while (ovector[1] < subjectLength) + { + if ((subject[ovector[1]] & 0xc0) != 0x80) + break; + ovector[1] += 1; + } + } + continue; + } + if (!PCRE2_HasMatches(rc, re, matchData)) + break; + + vectors[vectorMatchesCount].position = subject + ovector[2 * groupIndex] - subject; + vectors[vectorMatchesCount].length = ovector[2 * groupIndex + 1] - ovector[2 * groupIndex]; + vectorMatchesCount++; + } + + // Build values + for (int i = 0; i < vectorMatchesCount; i++) + { + PCRE2_VALUE value = { 0 }; + PCRE2_VECTOR current = vectors[i]; + PCRE2_VECTOR last = vectors[i - 1]; + + // Check for unmatched string + if (current.position != 0) + { + if (!i) + { + int length = current.position; + value.matched = qfalse; + PCRE2_AddValue(&value, (char*)subject, length, values); + } + else if (i > 0) + { + int pos = last.position + last.length; + if (pos != current.position) + { + int length = current.position - pos; + value.matched = qfalse; + PCRE2_AddValue(&value, (char*)subject + pos, length, values); + } + } + } + + // Matched string + value.matched = qtrue; + PCRE2_AddValue(&value, (char*)subject + current.position, current.length, values); + } + pcre2_match_data_free(matchData); + pcre2_code_free(re); + + return values; +} + +void PCRE2_FreeValues(PCRE2_VALUES* values) +{ + if (values != NULL) + { + if (values->results != NULL) + free(values->results); + free(values); + } + values = NULL; +} + +PCRE2_VALUES* PCRE2_Match(PCRE2_SPTR subject, PCRE2_SPTR regex) +{ + PCRE2_VALUES* matches = (PCRE2_VALUES*)calloc(1, sizeof(PCRE2_VALUES)); + PCRE2_VALUES* values = PCRE2_Compile(subject, regex); + + for (int i = 0; i < values->count; i++) + { + if (values->results[i].matched) + { + PCRE2_AddValue(&values->results[i], values->results[i].string, strlen(values->results[i].string), matches); + } + } + PCRE2_FreeValues(values); + return matches; +} + +PCRE2_VALUES* PCRE2_Split(PCRE2_SPTR subject, PCRE2_SPTR regex) +{ + PCRE2_VALUES* splits = (PCRE2_VALUES*)calloc(1, sizeof(PCRE2_VALUES)); + PCRE2_VALUES* values = PCRE2_Compile(subject, regex); + + for (int i = 0; i < values->count; i++) + { + if (!values->results[i].matched) + { + PCRE2_AddValue(&values->results[i], values->results[i].string, strlen(values->results[i].string), splits); + } + } + PCRE2_FreeValues(values); + return splits; +} + +char* PCRE2_Replace(PCRE2_SPTR subject, PCRE2_SPTR regex, const char* replace) +{ + char* string = (char*)calloc(MAX_STRING_CHARS, sizeof(char)); + PCRE2_VALUES* values = PCRE2_Compile(subject, regex); + + for (int i = 0; i < values->count; i++) + strcat(string, !values->results[i].matched ? values->results[i].string : replace); + PCRE2_FreeValues(values); + return string; +} diff --git a/src/data/regex.h b/src/data/regex.h index 09a18bc..86189bd 100644 --- a/src/data/regex.h +++ b/src/data/regex.h @@ -1,120 +1,120 @@ -#pragma once -#define PCRE2_CODE_UNIT_WIDTH 8 - -#include -#include - -typedef struct -{ - char string[MAX_STRING_CHARS]; - qboolean matched; -} PCRE2_VALUE; - -typedef struct -{ - PCRE2_VALUE* results; - size_t count; -} PCRE2_VALUES; - -typedef struct -{ - int position; - size_t length; -} PCRE2_VECTOR; - -/// -/// Get all splited string in an array from the specified input stringand regex. -/// -void GScr_RegexSplit(); - -/// -/// Get all matches in an array from the specified input string and regex. -/// -void GScr_RegexMatch(); - -/// -/// Replace all matches with a specific string. -/// -void GScr_RegexReplace(); - -/// -/// Get the options with which the regex was compiled and extract the UTF state. -/// -/// The re code. -/// The out option bits -/// -qboolean PCRE2_GetUTFOption(pcre2_code* re, uint32_t* optionBits); - -/// -/// Find the newline convention and see whether CRLF is a valid newline sequence. -/// -/// The re code. -/// The out newline. -/// -qboolean PCRE2_IsNewlineCRLF(pcre2_code* re, uint32_t* newline); - -/// -/// Check if a match data contains matches. -/// -/// The match RC from pcre2_match. -/// The re code. -/// The match data. -/// -qboolean PCRE2_HasMatches(int rc, pcre2_code* re, pcre2_match_data* matchData); - -/// -/// Check if a re successfully compiled. -/// -/// The re code. -/// The out error code. -/// The out error offset. -/// -qboolean PCRE2_CompileSuccess(pcre2_code* re, int* errorCode, PCRE2_SIZE* errorOffset); - -/// -/// Add a value to the provided values struct. -/// -/// The ref to a new value. -/// The string to add. -/// The length of the string. -/// The pointer to the values struct. -void PCRE2_AddValue(PCRE2_VALUE* value, char* string, int length, PCRE2_VALUES* values); - -/// -/// Compile a regex with the provided string and gets all different occurences type. -/// -/// The string to test with a regex. -/// The regex pattern. -/// -PCRE2_VALUES* PCRE2_Compile(PCRE2_SPTR subject, PCRE2_SPTR regex); - -/// -/// Free the values. -/// -/// The values pointer struct. -void PCRE2_FreeValues(PCRE2_VALUES* values); - -/// -/// Get all matches from the provided string and regex pattern. -/// -/// The string to test with a regex. -/// The regex pattern. -/// -PCRE2_VALUES* PCRE2_Match(PCRE2_SPTR subject, PCRE2_SPTR regex); - -/// -/// Get all splits from the provided string and regex pattern. -/// -/// The string to test with a regex. -/// The regex pattern. -/// -PCRE2_VALUES* PCRE2_Split(PCRE2_SPTR subject, PCRE2_SPTR regex); - -/// -/// Replace all matches from the provided string and regex pattern. -/// -/// The string to test with a regex. -/// The regex pattern. -/// The string to replace all matches. -/// -char* PCRE2_Replace(PCRE2_SPTR subject, PCRE2_SPTR regex, const char* replace); +#pragma once +#define PCRE2_CODE_UNIT_WIDTH 8 + +#include +#include + +typedef struct +{ + char string[MAX_STRING_CHARS]; + qboolean matched; +} PCRE2_VALUE; + +typedef struct +{ + PCRE2_VALUE* results; + size_t count; +} PCRE2_VALUES; + +typedef struct +{ + int position; + size_t length; +} PCRE2_VECTOR; + +/// +/// Get all splited string in an array from the specified input stringand regex. +/// +void GScr_RegexSplit(); + +/// +/// Get all matches in an array from the specified input string and regex. +/// +void GScr_RegexMatch(); + +/// +/// Replace all matches with a specific string. +/// +void GScr_RegexReplace(); + +/// +/// Get the options with which the regex was compiled and extract the UTF state. +/// +/// The re code. +/// The out option bits +/// +qboolean PCRE2_GetUTFOption(pcre2_code* re, uint32_t* optionBits); + +/// +/// Find the newline convention and see whether CRLF is a valid newline sequence. +/// +/// The re code. +/// The out newline. +/// +qboolean PCRE2_IsNewlineCRLF(pcre2_code* re, uint32_t* newline); + +/// +/// Check if a match data contains matches. +/// +/// The match RC from pcre2_match. +/// The re code. +/// The match data. +/// +qboolean PCRE2_HasMatches(int rc, pcre2_code* re, pcre2_match_data* matchData); + +/// +/// Check if a re successfully compiled. +/// +/// The re code. +/// The out error code. +/// The out error offset. +/// +qboolean PCRE2_CompileSuccess(pcre2_code* re, int* errorCode, PCRE2_SIZE* errorOffset); + +/// +/// Add a value to the provided values struct. +/// +/// The ref to a new value. +/// The string to add. +/// The length of the string. +/// The pointer to the values struct. +void PCRE2_AddValue(PCRE2_VALUE* value, char* string, int length, PCRE2_VALUES* values); + +/// +/// Compile a regex with the provided string and gets all different occurences type. +/// +/// The string to test with a regex. +/// The regex pattern. +/// +PCRE2_VALUES* PCRE2_Compile(PCRE2_SPTR subject, PCRE2_SPTR regex); + +/// +/// Free the values. +/// +/// The values pointer struct. +void PCRE2_FreeValues(PCRE2_VALUES* values); + +/// +/// Get all matches from the provided string and regex pattern. +/// +/// The string to test with a regex. +/// The regex pattern. +/// +PCRE2_VALUES* PCRE2_Match(PCRE2_SPTR subject, PCRE2_SPTR regex); + +/// +/// Get all splits from the provided string and regex pattern. +/// +/// The string to test with a regex. +/// The regex pattern. +/// +PCRE2_VALUES* PCRE2_Split(PCRE2_SPTR subject, PCRE2_SPTR regex); + +/// +/// Replace all matches from the provided string and regex pattern. +/// +/// The string to test with a regex. +/// The regex pattern. +/// The string to replace all matches. +/// +char* PCRE2_Replace(PCRE2_SPTR subject, PCRE2_SPTR regex, const char* replace); diff --git a/src/data/zip.h b/src/data/zip.h index c178d84..620f078 100644 --- a/src/data/zip.h +++ b/src/data/zip.h @@ -1,70 +1,70 @@ -#pragma once -#include "file.h" - -#include -#include - -/// -/// Add a file to the archive. -/// -void GScr_ZIP_Add(); - -/// -/// Rename a file in the archive. -/// -void GScr_ZIP_Rename(); - -/// -/// Delete a file in the archive. -/// -void GScr_ZIP_Delete(); - -/// -/// Open an archive. -/// -void GScr_ZIP_Open(); - -/// -/// Close the archive. -/// -void GScr_ZIP_Close(); - -/// -/// Add a file to the archive. -/// -/// The zip archive. -/// The filepath to add. -/// The output path in the archive. -/// -qboolean ZIP_Add(zip_t* zip, const char* filepath, const char* outpath); - -/// -/// Rename a file in the archive. -/// -/// The zip archive. -/// The filepath to rename. -/// The renamed path. -/// -qboolean ZIP_Rename(zip_t* zip, const char* filepath, const char* renamepath); - -/// -/// Delete a file in the archive. -/// -/// The zip archive. -/// The filepath to delete. -/// -qboolean ZIP_Delete(zip_t* zip, const char* filepath); - -/// -/// Open an archive. -/// -/// The zip filepath. -/// -zip_t* ZIP_Open(const char* path); - -/// -/// Close the archive. -/// -/// The zip archive. -/// -qboolean ZIP_Close(zip_t* zip); +#pragma once +#include "file.h" + +#include +#include + +/// +/// Add a file to the archive. +/// +void GScr_ZIP_Add(); + +/// +/// Rename a file in the archive. +/// +void GScr_ZIP_Rename(); + +/// +/// Delete a file in the archive. +/// +void GScr_ZIP_Delete(); + +/// +/// Open an archive. +/// +void GScr_ZIP_Open(); + +/// +/// Close the archive. +/// +void GScr_ZIP_Close(); + +/// +/// Add a file to the archive. +/// +/// The zip archive. +/// The filepath to add. +/// The output path in the archive. +/// +qboolean ZIP_Add(zip_t* zip, const char* filepath, const char* outpath); + +/// +/// Rename a file in the archive. +/// +/// The zip archive. +/// The filepath to rename. +/// The renamed path. +/// +qboolean ZIP_Rename(zip_t* zip, const char* filepath, const char* renamepath); + +/// +/// Delete a file in the archive. +/// +/// The zip archive. +/// The filepath to delete. +/// +qboolean ZIP_Delete(zip_t* zip, const char* filepath); + +/// +/// Open an archive. +/// +/// The zip filepath. +/// +zip_t* ZIP_Open(const char* path); + +/// +/// Close the archive. +/// +/// The zip archive. +/// +qboolean ZIP_Close(zip_t* zip); diff --git a/src/linq/delegates.h b/src/linq/delegates.h index 65ecf11..9ec7179 100644 --- a/src/linq/delegates.h +++ b/src/linq/delegates.h @@ -1,17 +1,17 @@ -#pragma once - -/// -/// Project data in a collection using delegates, -/// the same way select clause in a SQL database to fetch specific columns of a table. -/// -void GScr_LINQ_Select(); - -/// -/// Executes a provided function for each array element. -/// -void GScr_LINQ_Foreach(); - -/// -/// Aggregate the result of multiple delegate. -/// -void GScr_LINQ_Aggregate(); +#pragma once + +/// +/// Project data in a collection using delegates, +/// the same way select clause in a SQL database to fetch specific columns of a table. +/// +void GScr_LINQ_Select(); + +/// +/// Executes a provided function for each array element. +/// +void GScr_LINQ_Foreach(); + +/// +/// Aggregate the result of multiple delegate. +/// +void GScr_LINQ_Aggregate(); diff --git a/src/linq/enumerables.c b/src/linq/enumerables.c index cac5eed..600048c 100644 --- a/src/linq/enumerables.c +++ b/src/linq/enumerables.c @@ -1,762 +1,762 @@ -#include "enumerables.h" -#include "utils/stringutils.h" -#include "utils/polycmp.h" -#include "utils/utils.h" - -#include -#include -#include - -void GScr_LINQ_Reverse() -{ - CHECK_PARAMS(1, "Usage: Reverse()"); - - VariableValueArray array = Plugin_Scr_GetArray(0); - Plugin_Scr_MakeArray(); - - for (int i = array.length - 1; i > -1; i--) - { - Plugin_Scr_AddVariable(array.items[i]); - Plugin_Scr_AddArray(); - } - Plugin_Scr_FreeArray(&array); -} - -void GScr_LINQ_Min() -{ - CHECK_PARAMS(1, "Usage: Min()"); - - VariableValueArray array = Plugin_Scr_GetArray(0); - int flags = Plugin_Scr_GetArrayFlags(array); - - if (!array.length) - { - Plugin_Scr_FreeArray(&array); - return; - } - - if (HasFlag(flags, FLAG_STRING) || HasFlag(flags, FLAG_ISTRING)) - Scr_StringMin(array); - else if (HasFlag(flags, FLAG_VECTOR)) - Scr_VectorMin(array); - else if (HasFlag(flags, FLAG_INTEGER) || HasFlag(flags, FLAG_FLOAT)) - Scr_NumberMin(array, flags); - Plugin_Scr_FreeArray(&array); -} - -void Scr_StringMin(VariableValueArray array) -{ - char* result = (char *)Plugin_SL_ConvertToString(array.items[0].u.stringValue); - int currentLength = strlen(result); - - for (int i = 1; i < array.length; i++) - { - char* value = (char*)Plugin_SL_ConvertToString(array.items[i].u.stringValue); - int length = strlen(value); - - if (length < currentLength) - { - currentLength = length; - result = value; - } - } - Plugin_Scr_AddString(result); -} - -void Scr_VectorMin(VariableValueArray array) -{ - vec3_t zero = { 0, 0, 0 }; - float* result = (float*)array.items[0].u.vectorValue; - float currentDistance = VectorDistance(result, zero); - - for (int i = 1; i < array.length; i++) - { - float* value = (float*)array.items[i].u.vectorValue; - float distance = VectorDistance(value, zero); - - if (distance < currentDistance) - { - currentDistance = distance; - result = value; - } - } - Plugin_Scr_AddVector(result); -} - -void Scr_NumberMin(VariableValueArray array, int flags) -{ - float result = array.items[0].type == VAR_INTEGER - ? array.items[0].u.intValue - : array.items[0].u.floatValue; - - for (int i = 1; i < array.length; i++) - { - if (array.items[i].type == VAR_INTEGER) - { - if (array.items[i].u.intValue < result) - result = array.items[i].u.intValue; - } - else if (array.items[i].type == VAR_FLOAT) - { - if (array.items[i].u.floatValue < result) - result = array.items[i].u.floatValue; - } - } - if (!HasFlag(flags, FLAG_FLOAT)) - Plugin_Scr_AddInt((int)result); - else - Plugin_Scr_AddFloat(result); -} - -void GScr_LINQ_Max() -{ - CHECK_PARAMS(1, "Usage: Max()"); - - VariableValueArray array = Plugin_Scr_GetArray(0); - uint32_t flags = Plugin_Scr_GetArrayFlags(array); - - if (!array.length) - { - Plugin_Scr_FreeArray(&array); - return; - } - - if (HasFlag(flags, FLAG_STRING) || HasFlag(flags, FLAG_ISTRING)) - Scr_StringMax(array); - else if (HasFlag(flags, FLAG_VECTOR)) - Scr_VectorMax(array); - else if (HasFlag(flags, FLAG_INTEGER) || HasFlag(flags, FLAG_FLOAT)) - Scr_NumberMax(array, flags); - Plugin_Scr_FreeArray(&array); -} - -void Scr_StringMax(VariableValueArray array) -{ - char* result = (char *)Plugin_SL_ConvertToString(array.items[0].u.stringValue); - int currentLength = strlen(result); - - for (int i = 1; i < array.length; i++) - { - char* value = (char*)Plugin_SL_ConvertToString(array.items[i].u.stringValue); - int length = strlen(value); - - if (length > currentLength) - { - currentLength = length; - result = value; - } - } - Plugin_Scr_AddString(result); -} - -void Scr_VectorMax(VariableValueArray array) -{ - vec3_t zero = { 0, 0, 0 }; - float* result = (float*)array.items[0].u.vectorValue; - float currentDistance = VectorDistance(result, zero); - - for (int i = 1; i < array.length; i++) - { - float* value = (float*)array.items[i].u.vectorValue; - float distance = VectorDistance(value, zero); - - if (distance > currentDistance) - { - currentDistance = distance; - result = value; - } - } - Plugin_Scr_AddVector(result); -} - -void Scr_NumberMax(VariableValueArray array, int flags) -{ - float result = array.items[0].type == VAR_INTEGER - ? array.items[0].u.intValue - : array.items[0].u.floatValue; - - for (int i = 0; i < array.length; i++) - { - if (array.items[i].type == VAR_INTEGER) - { - if (array.items[i].u.intValue > result) - result = array.items[i].u.intValue; - } - else if (array.items[i].type == VAR_FLOAT) - { - if (array.items[i].u.floatValue > result) - result = array.items[i].u.floatValue; - } - } - if (!HasFlag(flags, FLAG_FLOAT)) - Plugin_Scr_AddInt((int)result); - else - Plugin_Scr_AddFloat(result); -} - -void GScr_LINQ_Cast() -{ - CHECK_PARAMS(2, "Usage: Cast(, )"); - - VariableValueArray array = Plugin_Scr_GetArray(0); - const char *typename = Plugin_Scr_GetString(1); - - Plugin_Scr_MakeArray(); - if (strcasecmp(typename, "string") == 0) - Scr_StringCast(array); - else if (strcasecmp(typename, "int") == 0) - Scr_IntCast(array); - else if (strcasecmp(typename, "float") == 0) - Scr_FloatCast(array); - Plugin_Scr_FreeArray(&array); -} - -void Scr_StringCast(VariableValueArray array) -{ - for (int i = 0; i < array.length; i++) - { - switch (array.items[i].type) - { - case VAR_FLOAT: - { - Plugin_Scr_AddString(fmt("%f", array.items[i].u.floatValue)); - Plugin_Scr_AddArray(); - break; - } - case VAR_INTEGER: - { - Plugin_Scr_AddString(fmt("%d", array.items[i].u.intValue)); - Plugin_Scr_AddArray(); - break; - } - case VAR_STRING: - { - Plugin_Scr_AddVariable(array.items[i]); - Plugin_Scr_AddArray(); - break; - } - case VAR_VECTOR: - { - Plugin_Scr_AddString(fmt("(%f, %f, %f)", - array.items[i].u.vectorValue[0], - array.items[i].u.vectorValue[1], - array.items[i].u.vectorValue[2])); - Plugin_Scr_AddArray(); - break; - } - } - } -} - -void Scr_IntCast(VariableValueArray array) -{ - for (int i = 0; i < array.length; i++) - { - switch (array.items[i].type) - { - case VAR_FLOAT: - { - Plugin_Scr_AddInt((int)array.items[i].u.floatValue); - Plugin_Scr_AddArray(); - break; - } - case VAR_INTEGER: - { - Plugin_Scr_AddVariable(array.items[i]); - Plugin_Scr_AddArray(); - break; - } - case VAR_STRING: - { - const char* nptr = Plugin_SL_ConvertToString(array.items[i].u.stringValue); - char* endptr = NULL; - long number = strtol(nptr, &endptr, 10); - - if (*endptr == '\0') - { - Plugin_Scr_AddInt((int)number); - Plugin_Scr_AddArray(); - } - break; - } - } - } -} - -void Scr_FloatCast(VariableValueArray array) -{ - for (int i = 0; i < array.length; i++) - { - switch (array.items[i].type) - { - case VAR_FLOAT: - { - Plugin_Scr_AddVariable(array.items[i]); - Plugin_Scr_AddArray(); - break; - } - case VAR_INTEGER: - { - Plugin_Scr_AddFloat((float)array.items[i].u.intValue); - Plugin_Scr_AddArray(); - break; - } - case VAR_STRING: - { - const char* nptr = Plugin_SL_ConvertToString(array.items[i].u.stringValue); - char* endptr = NULL; - float number = strtof(nptr, &endptr); - - if (*endptr == '\0') - { - Plugin_Scr_AddFloat(number); - Plugin_Scr_AddArray(); - } - break; - } - } - } -} - -void GScr_LINQ_OfType() -{ - CHECK_PARAMS(2, "Usage: OfType(, )"); - - VariableValueArray array = Plugin_Scr_GetArray(0); - const char *typename = Plugin_Scr_GetString(1); - - int ofType = VAR_UNDEFINED; - if (strcasecmp(typename, "int") == 0) - ofType = VAR_INTEGER; - else if (strcasecmp(typename, "float") == 0) - ofType = VAR_FLOAT; - else if (strcasecmp(typename, "vector") == 0) - ofType = VAR_VECTOR; - else if (strcasecmp(typename, "array") == 0) - ofType = VAR_ARRAY; - else if (strcasecmp(typename, "struct") == 0) - ofType = VAR_OBJECT; - else if (strcasecmp(typename, "string") == 0) - ofType = VAR_STRING; - else if (strcasecmp(typename, "istring") == 0) - ofType = VAR_ISTRING; - else if (strcasecmp(typename, "ent") == 0) - ofType = VAR_ENTITY; - - Plugin_Scr_MakeArray(); - for (int i = 0; i < array.length; i++) - { - int type = (array.items[i].type == VAR_POINTER) - ? Plugin_Scr_GetObjectType(array.items[i].u.pointerValue) - : array.items[i].type; - if (ofType == type) - { - Plugin_Scr_AddVariable(array.items[i]); - Plugin_Scr_AddArray(); - } - } - Plugin_Scr_FreeArray(&array); -} - -void GScr_LINQ_Sort() -{ - CHECK_PARAMS(1, "Usage: Sort()"); - - VariableValueArray array = Plugin_Scr_GetArray(0); - uint32_t flags = Plugin_Scr_GetArrayFlags(array); - - Plugin_Scr_MakeArray(); - if (IsFlag(flags, FLAG_FLOAT)) - qsort(array.items, array.length, sizeof(VariableValue), Scr_FloatCmp); - else if (IsFlag(flags, FLAG_INTEGER)) - qsort(array.items, array.length, sizeof(VariableValue), Scr_IntCmp); - else if (IsFlag(flags, FLAG_STRING) || IsFlag(flags, FLAG_ISTRING)) - qsort(array.items, array.length, sizeof(VariableValue), Scr_StringCmp); - else if (IsFlag(flags, FLAG_VECTOR)) - qsort(array.items, array.length, sizeof(VariableValue), Scr_VectorCmp); - - for (int i = 0; i < array.length; i++) - { - Plugin_Scr_AddVariable(array.items[i]); - Plugin_Scr_AddArray(); - } - Plugin_Scr_FreeArray(&array); -} - -void GScr_LINQ_Average() -{ - CHECK_PARAMS(1, "Usage: Average()"); - - VariableValueArray array = Plugin_Scr_GetArray(0); - const uint32_t flags = Plugin_Scr_GetArrayFlags(array); - - if (IsFlag(flags, FLAG_VECTOR)) - Scr_VectorAverage(array); - else if (IsFlag(flags, FLAG_INTEGER) || IsFlag(flags, FLAG_FLOAT)) - Scr_NumberAverage(array, flags); - Plugin_Scr_FreeArray(&array); -} - -void Scr_VectorAverage(VariableValueArray array) -{ - int count = 0; - vec3_t vec = { 0, 0, 0 }; - - for (int i = 0; i < array.length; i++) - { - if (array.items[i].type == VAR_VECTOR) - { - vec[0] += array.items[i].u.vectorValue[0]; - vec[1] += array.items[i].u.vectorValue[1]; - vec[2] += array.items[i].u.vectorValue[2]; - count++; - } - } - vec[0] /= count; - vec[1] /= count; - vec[2] /= count; - - Plugin_Scr_AddVector(vec); -} - -void Scr_NumberAverage(VariableValueArray array, int flags) -{ - int count = 0; - float sum = 0; - - for (int i = 0; i < array.length; i++) - { - if (array.items[i].type == VAR_FLOAT) - sum += array.items[i].u.floatValue; - else - sum += array.items[i].u.intValue; - count++; - } - Plugin_Scr_AddFloat(sum / count); -} - -void GScr_LINQ_Sum() -{ - CHECK_PARAMS(1, "Usage: Sum()"); - - VariableValueArray array = Plugin_Scr_GetArray(0); - uint32_t flags = Plugin_Scr_GetArrayFlags(array); - - if (HasFlag(flags, FLAG_STRING) || HasFlag(flags, FLAG_ISTRING)) - Scr_StringSum(array); - else if (HasFlag(flags, FLAG_VECTOR)) - Scr_VectorSum(array); - else if (HasFlag(flags, FLAG_INTEGER) || HasFlag(flags, FLAG_FLOAT)) - Scr_NumberSum(array, flags); - Plugin_Scr_FreeArray(&array); -} - -void Scr_StringSum(VariableValueArray array) -{ - char result[MAX_STRING_CHARS] = { 0 }; - for (int i = 0; i < array.length; i++) - { - switch (array.items[i].type) - { - case VAR_INTEGER: - strcat(result, fmt("%d", array.items[i].u.intValue)); - break; - case VAR_FLOAT: - strcat(result, fmt("%f", array.items[i].u.floatValue)); - break; - case VAR_ISTRING: - case VAR_STRING: - strcat(result, fmt("%s", Plugin_SL_ConvertToString(array.items[i].u.stringValue))); - break; - } - } - Plugin_Scr_AddString(result); -} - -void Scr_VectorSum(VariableValueArray array) -{ - vec3_t sum = { 0, 0, 0 }; - for (int i = 0; i < array.length; i++) - { - if (array.items[i].type == VAR_VECTOR) - { - sum[0] += array.items[i].u.vectorValue[0]; - sum[1] += array.items[i].u.vectorValue[1]; - sum[2] += array.items[i].u.vectorValue[2]; - } - } - Plugin_Scr_AddVector(sum); -} - -void Scr_NumberSum(VariableValueArray array, int flags) -{ - float sum = 0; - for (int i = 0; i < array.length; i++) - { - switch (array.items[i].type) - { - case VAR_INTEGER: sum += array.items[i].u.intValue; break; - case VAR_FLOAT: sum += array.items[i].u.floatValue; break; - } - } - if (!HasFlag(flags, FLAG_FLOAT)) - Plugin_Scr_AddInt((int)sum); - else - Plugin_Scr_AddFloat(sum); -} - -void GScr_LINQ_Range() -{ - CHECK_PARAMS(3, "Usage: Range(, , )"); - - VariableValueArray array = Plugin_Scr_GetArray(0); - const int min = Plugin_Scr_GetInt(1); - const int max = Plugin_Scr_GetInt(2); - - if (min >= max || max < min) - { - Plugin_Scr_Error("Range() - Wrong min/max value"); - return; - } - - Plugin_Scr_MakeArray(); - for (int i = min; i < max; i++) - { - Plugin_Scr_AddVariable(array.items[i]); - Plugin_Scr_AddArray(); - } - Plugin_Scr_FreeArray(&array); -} - -void GScr_LINQ_Repeat() -{ - CHECK_PARAMS(2, "Usage: Repeat(, )"); - - VariableValueArray array = Plugin_Scr_GetArray(0); - const int count = Plugin_Scr_GetInt(1); - - Plugin_Scr_MakeArray(); - for (int r = 0; r < count; r++) - { - for (int i = 0; i < array.length; i++) - { - Plugin_Scr_AddVariable(array.items[i]); - Plugin_Scr_AddArray(); - } - } - Plugin_Scr_FreeArray(&array); -} - -void GScr_LINQ_Concat() -{ - CHECK_PARAMS(2, "Usage: Repeat(, )"); - - VariableValueArray arraySource = Plugin_Scr_GetArray(0); - VariableValueArray array = Plugin_Scr_GetArray(1); - - Plugin_Scr_MakeArray(); - for (int i = 0; i < arraySource.length; i++) - { - Plugin_Scr_AddVariable(arraySource.items[i]); - Plugin_Scr_AddArray(); - } - for (int i = 0; i < array.length; i++) - { - Plugin_Scr_AddVariable(array.items[i]); - Plugin_Scr_AddArray(); - } - Plugin_Scr_FreeArray(&arraySource); - Plugin_Scr_FreeArray(&array); -} - -void GScr_LINQ_Chunk() -{ - CHECK_PARAMS(2, "Usage: Chunk(, )"); - - VariableValueArray array = Plugin_Scr_GetArray(0); - const int count = Plugin_Scr_GetInt(1); - - Plugin_Scr_MakeArray(); - for (int i = 0; i < array.length && count; i++) - { - if (!(i % count)) - Plugin_Scr_MakeArray(); - - Plugin_Scr_AddVariable(array.items[i]); - Plugin_Scr_AddArray(); - - if (!((i + 1) % count) || i + 1 == array.length) - Plugin_Scr_AddArray(); - } - Plugin_Scr_FreeArray(&array); -} - -void GScr_LINQ_Contains() -{ - CHECK_PARAMS(2, "Usage: Contains(, )"); - - VariableValueArray array = Plugin_Scr_GetArray(0); - VariableValue element = *Plugin_Scr_SelectParam(1); - qboolean found = qfalse; - - for (int i = 0; i < array.length; i++) - { - VariableValue current = array.items[i]; - - if (current.type == element.type) - { - switch (array.items[i].type) - { - case VAR_VECTOR: - if (current.u.vectorValue[0] == element.u.vectorValue[0] && - current.u.vectorValue[1] == element.u.vectorValue[1] && - current.u.vectorValue[2] == element.u.vectorValue[2]) - break; - continue; - case VAR_INTEGER: - if (current.u.intValue == element.u.intValue) - break; - continue; - case VAR_FLOAT: - if (current.u.floatValue == element.u.floatValue) - break; - continue; - case VAR_ISTRING: - case VAR_STRING: - if (strcmp(Plugin_SL_ConvertToString(current.u.stringValue), - Plugin_SL_ConvertToString(element.u.stringValue)) == 0) - break; - continue; - case VAR_POINTER: - if (current.u.pointerValue == element.u.pointerValue) - break; - continue; - default: - continue; - } - found = qtrue; - break; - } - } - Plugin_Scr_AddBool(found); -} - -void GScr_LINQ_IndexOf() -{ - CHECK_PARAMS(2, "Usage: IndexOf(, )"); - - VariableValueArray array = Plugin_Scr_GetArray(0); - VariableValue element = *Plugin_Scr_SelectParam(1); - int found = -1; - - for (int i = 0; i < array.length; i++) - { - VariableValue current = array.items[i]; - - if (current.type == element.type) - { - switch (array.items[i].type) - { - case VAR_VECTOR: - if (current.u.vectorValue[0] == element.u.vectorValue[0] && - current.u.vectorValue[1] == element.u.vectorValue[1] && - current.u.vectorValue[2] == element.u.vectorValue[2]) - break; - continue; - case VAR_INTEGER: - if (current.u.intValue == element.u.intValue) - break; - continue; - case VAR_FLOAT: - if (current.u.floatValue == element.u.floatValue) - break; - continue; - case VAR_ISTRING: - case VAR_STRING: - if (strcmp(Plugin_SL_ConvertToString(current.u.stringValue), - Plugin_SL_ConvertToString(element.u.stringValue)) == 0) - break; - continue; - case VAR_POINTER: - if (current.u.pointerValue == element.u.pointerValue) - break; - continue; - default: - continue; - } - found = i; - break; - } - } - Plugin_Scr_FreeArray(&array); - Plugin_Scr_AddInt(found); -} - -void GScr_LINQ_Remove() -{ - CHECK_PARAMS(2, "Usage: Remove(, )"); - - VariableValueArray array = Plugin_Scr_GetArray(0); - VariableValue element = *Plugin_Scr_SelectParam(1); - - Plugin_Scr_MakeArray(); - for (int i = 0; i < array.length; i++) - { - VariableValue current = array.items[i]; - - if (current.type == element.type) - { - switch (array.items[i].type) - { - case VAR_VECTOR: - if (current.u.vectorValue[0] == element.u.vectorValue[0] && - current.u.vectorValue[1] == element.u.vectorValue[1] && - current.u.vectorValue[2] == element.u.vectorValue[2]) - continue; - break; - case VAR_INTEGER: - if (current.u.intValue == element.u.intValue) - continue; - break; - case VAR_FLOAT: - if (current.u.floatValue == element.u.floatValue) - continue; - break; - case VAR_ISTRING: - case VAR_STRING: - if (strcmp(Plugin_SL_ConvertToString(current.u.stringValue), - Plugin_SL_ConvertToString(element.u.stringValue)) == 0) - continue; - break; - case VAR_POINTER: - if (current.u.pointerValue == element.u.pointerValue) - continue; - break; - } - } - Plugin_Scr_AddVariable(current); - Plugin_Scr_AddArray(); - } - Plugin_Scr_FreeArray(&array); -} - -void GScr_LINQ_RemoveAt() -{ - CHECK_PARAMS(2, "Usage: RemoveAt(, )"); - - VariableValueArray array = Plugin_Scr_GetArray(0); - int index = Plugin_Scr_GetInt(1); - - Plugin_Scr_MakeArray(); - for (int i = 0; i < array.length; i++) - { - VariableValue current = array.items[i]; - - if (i == index) - continue; - - Plugin_Scr_AddVariable(current); - Plugin_Scr_AddArray(); - } - Plugin_Scr_FreeArray(&array); -} +#include "enumerables.h" +#include "utils/polycmp.h" +#include "utils/stringutils.h" +#include "utils/utils.h" + +#include +#include +#include + +void GScr_LINQ_Reverse() +{ + CHECK_PARAMS(1, "Usage: Reverse()"); + + VariableValueArray array = Plugin_Scr_GetArray(0); + Plugin_Scr_MakeArray(); + + for (int i = array.length - 1; i > -1; i--) + { + Plugin_Scr_AddVariable(array.items[i]); + Plugin_Scr_AddArray(); + } + Plugin_Scr_FreeArray(&array); +} + +void GScr_LINQ_Min() +{ + CHECK_PARAMS(1, "Usage: Min()"); + + VariableValueArray array = Plugin_Scr_GetArray(0); + int flags = Plugin_Scr_GetArrayFlags(array); + + if (!array.length) + { + Plugin_Scr_FreeArray(&array); + return; + } + + if (HasFlag(flags, FLAG_STRING) || HasFlag(flags, FLAG_ISTRING)) + Scr_StringMin(array); + else if (HasFlag(flags, FLAG_VECTOR)) + Scr_VectorMin(array); + else if (HasFlag(flags, FLAG_INTEGER) || HasFlag(flags, FLAG_FLOAT)) + Scr_NumberMin(array, flags); + Plugin_Scr_FreeArray(&array); +} + +void Scr_StringMin(VariableValueArray array) +{ + char* result = (char*)Plugin_SL_ConvertToString(array.items[0].u.stringValue); + int currentLength = strlen(result); + + for (int i = 1; i < array.length; i++) + { + char* value = (char*)Plugin_SL_ConvertToString(array.items[i].u.stringValue); + int length = strlen(value); + + if (length < currentLength) + { + currentLength = length; + result = value; + } + } + Plugin_Scr_AddString(result); +} + +void Scr_VectorMin(VariableValueArray array) +{ + vec3_t zero = { 0, 0, 0 }; + float* result = (float*)array.items[0].u.vectorValue; + float currentDistance = VectorDistance(result, zero); + + for (int i = 1; i < array.length; i++) + { + float* value = (float*)array.items[i].u.vectorValue; + float distance = VectorDistance(value, zero); + + if (distance < currentDistance) + { + currentDistance = distance; + result = value; + } + } + Plugin_Scr_AddVector(result); +} + +void Scr_NumberMin(VariableValueArray array, int flags) +{ + float result = array.items[0].type == VAR_INTEGER ? array.items[0].u.intValue : array.items[0].u.floatValue; + + for (int i = 1; i < array.length; i++) + { + if (array.items[i].type == VAR_INTEGER) + { + if (array.items[i].u.intValue < result) + result = array.items[i].u.intValue; + } + else if (array.items[i].type == VAR_FLOAT) + { + if (array.items[i].u.floatValue < result) + result = array.items[i].u.floatValue; + } + } + if (!HasFlag(flags, FLAG_FLOAT)) + Plugin_Scr_AddInt((int)result); + else + Plugin_Scr_AddFloat(result); +} + +void GScr_LINQ_Max() +{ + CHECK_PARAMS(1, "Usage: Max()"); + + VariableValueArray array = Plugin_Scr_GetArray(0); + uint32_t flags = Plugin_Scr_GetArrayFlags(array); + + if (!array.length) + { + Plugin_Scr_FreeArray(&array); + return; + } + + if (HasFlag(flags, FLAG_STRING) || HasFlag(flags, FLAG_ISTRING)) + Scr_StringMax(array); + else if (HasFlag(flags, FLAG_VECTOR)) + Scr_VectorMax(array); + else if (HasFlag(flags, FLAG_INTEGER) || HasFlag(flags, FLAG_FLOAT)) + Scr_NumberMax(array, flags); + Plugin_Scr_FreeArray(&array); +} + +void Scr_StringMax(VariableValueArray array) +{ + char* result = (char*)Plugin_SL_ConvertToString(array.items[0].u.stringValue); + int currentLength = strlen(result); + + for (int i = 1; i < array.length; i++) + { + char* value = (char*)Plugin_SL_ConvertToString(array.items[i].u.stringValue); + int length = strlen(value); + + if (length > currentLength) + { + currentLength = length; + result = value; + } + } + Plugin_Scr_AddString(result); +} + +void Scr_VectorMax(VariableValueArray array) +{ + vec3_t zero = { 0, 0, 0 }; + float* result = (float*)array.items[0].u.vectorValue; + float currentDistance = VectorDistance(result, zero); + + for (int i = 1; i < array.length; i++) + { + float* value = (float*)array.items[i].u.vectorValue; + float distance = VectorDistance(value, zero); + + if (distance > currentDistance) + { + currentDistance = distance; + result = value; + } + } + Plugin_Scr_AddVector(result); +} + +void Scr_NumberMax(VariableValueArray array, int flags) +{ + float result = array.items[0].type == VAR_INTEGER ? array.items[0].u.intValue : array.items[0].u.floatValue; + + for (int i = 0; i < array.length; i++) + { + if (array.items[i].type == VAR_INTEGER) + { + if (array.items[i].u.intValue > result) + result = array.items[i].u.intValue; + } + else if (array.items[i].type == VAR_FLOAT) + { + if (array.items[i].u.floatValue > result) + result = array.items[i].u.floatValue; + } + } + if (!HasFlag(flags, FLAG_FLOAT)) + Plugin_Scr_AddInt((int)result); + else + Plugin_Scr_AddFloat(result); +} + +void GScr_LINQ_Cast() +{ + CHECK_PARAMS(2, "Usage: Cast(, )"); + + VariableValueArray array = Plugin_Scr_GetArray(0); + const char* typename = Plugin_Scr_GetString(1); + + Plugin_Scr_MakeArray(); + if (strcasecmp(typename, "string") == 0) + Scr_StringCast(array); + else if (strcasecmp(typename, "int") == 0) + Scr_IntCast(array); + else if (strcasecmp(typename, "float") == 0) + Scr_FloatCast(array); + Plugin_Scr_FreeArray(&array); +} + +void Scr_StringCast(VariableValueArray array) +{ + for (int i = 0; i < array.length; i++) + { + switch (array.items[i].type) + { + case VAR_FLOAT: + { + Plugin_Scr_AddString(fmt("%f", array.items[i].u.floatValue)); + Plugin_Scr_AddArray(); + break; + } + case VAR_INTEGER: + { + Plugin_Scr_AddString(fmt("%d", array.items[i].u.intValue)); + Plugin_Scr_AddArray(); + break; + } + case VAR_STRING: + { + Plugin_Scr_AddVariable(array.items[i]); + Plugin_Scr_AddArray(); + break; + } + case VAR_VECTOR: + { + Plugin_Scr_AddString(fmt("(%f, %f, %f)", array.items[i].u.vectorValue[0], array.items[i].u.vectorValue[1], + array.items[i].u.vectorValue[2])); + Plugin_Scr_AddArray(); + break; + } + } + } +} + +void Scr_IntCast(VariableValueArray array) +{ + for (int i = 0; i < array.length; i++) + { + switch (array.items[i].type) + { + case VAR_FLOAT: + { + Plugin_Scr_AddInt((int)array.items[i].u.floatValue); + Plugin_Scr_AddArray(); + break; + } + case VAR_INTEGER: + { + Plugin_Scr_AddVariable(array.items[i]); + Plugin_Scr_AddArray(); + break; + } + case VAR_STRING: + { + const char* nptr = Plugin_SL_ConvertToString(array.items[i].u.stringValue); + char* endptr = NULL; + long number = strtol(nptr, &endptr, 10); + + if (*endptr == '\0') + { + Plugin_Scr_AddInt((int)number); + Plugin_Scr_AddArray(); + } + break; + } + } + } +} + +void Scr_FloatCast(VariableValueArray array) +{ + for (int i = 0; i < array.length; i++) + { + switch (array.items[i].type) + { + case VAR_FLOAT: + { + Plugin_Scr_AddVariable(array.items[i]); + Plugin_Scr_AddArray(); + break; + } + case VAR_INTEGER: + { + Plugin_Scr_AddFloat((float)array.items[i].u.intValue); + Plugin_Scr_AddArray(); + break; + } + case VAR_STRING: + { + const char* nptr = Plugin_SL_ConvertToString(array.items[i].u.stringValue); + char* endptr = NULL; + float number = strtof(nptr, &endptr); + + if (*endptr == '\0') + { + Plugin_Scr_AddFloat(number); + Plugin_Scr_AddArray(); + } + break; + } + } + } +} + +void GScr_LINQ_OfType() +{ + CHECK_PARAMS(2, "Usage: OfType(, )"); + + VariableValueArray array = Plugin_Scr_GetArray(0); + const char* typename = Plugin_Scr_GetString(1); + + int ofType = VAR_UNDEFINED; + if (strcasecmp(typename, "int") == 0) + ofType = VAR_INTEGER; + else if (strcasecmp(typename, "float") == 0) + ofType = VAR_FLOAT; + else if (strcasecmp(typename, "vector") == 0) + ofType = VAR_VECTOR; + else if (strcasecmp(typename, "array") == 0) + ofType = VAR_ARRAY; + else if (strcasecmp(typename, "struct") == 0) + ofType = VAR_OBJECT; + else if (strcasecmp(typename, "string") == 0) + ofType = VAR_STRING; + else if (strcasecmp(typename, "istring") == 0) + ofType = VAR_ISTRING; + else if (strcasecmp(typename, "ent") == 0) + ofType = VAR_ENTITY; + + Plugin_Scr_MakeArray(); + for (int i = 0; i < array.length; i++) + { + int type = (array.items[i].type == VAR_POINTER) ? Plugin_Scr_GetObjectType(array.items[i].u.pointerValue) + : array.items[i].type; + if (ofType == type) + { + Plugin_Scr_AddVariable(array.items[i]); + Plugin_Scr_AddArray(); + } + } + Plugin_Scr_FreeArray(&array); +} + +void GScr_LINQ_Sort() +{ + CHECK_PARAMS(1, "Usage: Sort()"); + + VariableValueArray array = Plugin_Scr_GetArray(0); + uint32_t flags = Plugin_Scr_GetArrayFlags(array); + + Plugin_Scr_MakeArray(); + if (IsFlag(flags, FLAG_FLOAT)) + qsort(array.items, array.length, sizeof(VariableValue), Scr_FloatCmp); + else if (IsFlag(flags, FLAG_INTEGER)) + qsort(array.items, array.length, sizeof(VariableValue), Scr_IntCmp); + else if (IsFlag(flags, FLAG_STRING) || IsFlag(flags, FLAG_ISTRING)) + qsort(array.items, array.length, sizeof(VariableValue), Scr_StringCmp); + else if (IsFlag(flags, FLAG_VECTOR)) + qsort(array.items, array.length, sizeof(VariableValue), Scr_VectorCmp); + + for (int i = 0; i < array.length; i++) + { + Plugin_Scr_AddVariable(array.items[i]); + Plugin_Scr_AddArray(); + } + Plugin_Scr_FreeArray(&array); +} + +void GScr_LINQ_Average() +{ + CHECK_PARAMS(1, "Usage: Average()"); + + VariableValueArray array = Plugin_Scr_GetArray(0); + const uint32_t flags = Plugin_Scr_GetArrayFlags(array); + + if (IsFlag(flags, FLAG_VECTOR)) + Scr_VectorAverage(array); + else if (IsFlag(flags, FLAG_INTEGER) || IsFlag(flags, FLAG_FLOAT)) + Scr_NumberAverage(array, flags); + Plugin_Scr_FreeArray(&array); +} + +void Scr_VectorAverage(VariableValueArray array) +{ + int count = 0; + vec3_t vec = { 0, 0, 0 }; + + for (int i = 0; i < array.length; i++) + { + if (array.items[i].type == VAR_VECTOR) + { + vec[0] += array.items[i].u.vectorValue[0]; + vec[1] += array.items[i].u.vectorValue[1]; + vec[2] += array.items[i].u.vectorValue[2]; + count++; + } + } + vec[0] /= count; + vec[1] /= count; + vec[2] /= count; + + Plugin_Scr_AddVector(vec); +} + +void Scr_NumberAverage(VariableValueArray array, int flags) +{ + int count = 0; + float sum = 0; + + for (int i = 0; i < array.length; i++) + { + if (array.items[i].type == VAR_FLOAT) + sum += array.items[i].u.floatValue; + else + sum += array.items[i].u.intValue; + count++; + } + Plugin_Scr_AddFloat(sum / count); +} + +void GScr_LINQ_Sum() +{ + CHECK_PARAMS(1, "Usage: Sum()"); + + VariableValueArray array = Plugin_Scr_GetArray(0); + uint32_t flags = Plugin_Scr_GetArrayFlags(array); + + if (HasFlag(flags, FLAG_STRING) || HasFlag(flags, FLAG_ISTRING)) + Scr_StringSum(array); + else if (HasFlag(flags, FLAG_VECTOR)) + Scr_VectorSum(array); + else if (HasFlag(flags, FLAG_INTEGER) || HasFlag(flags, FLAG_FLOAT)) + Scr_NumberSum(array, flags); + Plugin_Scr_FreeArray(&array); +} + +void Scr_StringSum(VariableValueArray array) +{ + char result[MAX_STRING_CHARS] = { 0 }; + for (int i = 0; i < array.length; i++) + { + switch (array.items[i].type) + { + case VAR_INTEGER: + strcat(result, fmt("%d", array.items[i].u.intValue)); + break; + case VAR_FLOAT: + strcat(result, fmt("%f", array.items[i].u.floatValue)); + break; + case VAR_ISTRING: + case VAR_STRING: + strcat(result, fmt("%s", Plugin_SL_ConvertToString(array.items[i].u.stringValue))); + break; + } + } + Plugin_Scr_AddString(result); +} + +void Scr_VectorSum(VariableValueArray array) +{ + vec3_t sum = { 0, 0, 0 }; + for (int i = 0; i < array.length; i++) + { + if (array.items[i].type == VAR_VECTOR) + { + sum[0] += array.items[i].u.vectorValue[0]; + sum[1] += array.items[i].u.vectorValue[1]; + sum[2] += array.items[i].u.vectorValue[2]; + } + } + Plugin_Scr_AddVector(sum); +} + +void Scr_NumberSum(VariableValueArray array, int flags) +{ + float sum = 0; + for (int i = 0; i < array.length; i++) + { + switch (array.items[i].type) + { + case VAR_INTEGER: + sum += array.items[i].u.intValue; + break; + case VAR_FLOAT: + sum += array.items[i].u.floatValue; + break; + } + } + if (!HasFlag(flags, FLAG_FLOAT)) + Plugin_Scr_AddInt((int)sum); + else + Plugin_Scr_AddFloat(sum); +} + +void GScr_LINQ_Range() +{ + CHECK_PARAMS(3, "Usage: Range(, , )"); + + VariableValueArray array = Plugin_Scr_GetArray(0); + const int min = Plugin_Scr_GetInt(1); + const int max = Plugin_Scr_GetInt(2); + + if (min >= max || max < min) + { + Plugin_Scr_Error("Range() - Wrong min/max value"); + return; + } + + Plugin_Scr_MakeArray(); + for (int i = min; i < max; i++) + { + Plugin_Scr_AddVariable(array.items[i]); + Plugin_Scr_AddArray(); + } + Plugin_Scr_FreeArray(&array); +} + +void GScr_LINQ_Repeat() +{ + CHECK_PARAMS(2, "Usage: Repeat(, )"); + + VariableValueArray array = Plugin_Scr_GetArray(0); + const int count = Plugin_Scr_GetInt(1); + + Plugin_Scr_MakeArray(); + for (int r = 0; r < count; r++) + { + for (int i = 0; i < array.length; i++) + { + Plugin_Scr_AddVariable(array.items[i]); + Plugin_Scr_AddArray(); + } + } + Plugin_Scr_FreeArray(&array); +} + +void GScr_LINQ_Concat() +{ + CHECK_PARAMS(2, "Usage: Repeat(, )"); + + VariableValueArray arraySource = Plugin_Scr_GetArray(0); + VariableValueArray array = Plugin_Scr_GetArray(1); + + Plugin_Scr_MakeArray(); + for (int i = 0; i < arraySource.length; i++) + { + Plugin_Scr_AddVariable(arraySource.items[i]); + Plugin_Scr_AddArray(); + } + for (int i = 0; i < array.length; i++) + { + Plugin_Scr_AddVariable(array.items[i]); + Plugin_Scr_AddArray(); + } + Plugin_Scr_FreeArray(&arraySource); + Plugin_Scr_FreeArray(&array); +} + +void GScr_LINQ_Chunk() +{ + CHECK_PARAMS(2, "Usage: Chunk(, )"); + + VariableValueArray array = Plugin_Scr_GetArray(0); + const int count = Plugin_Scr_GetInt(1); + + Plugin_Scr_MakeArray(); + for (int i = 0; i < array.length && count; i++) + { + if (!(i % count)) + Plugin_Scr_MakeArray(); + + Plugin_Scr_AddVariable(array.items[i]); + Plugin_Scr_AddArray(); + + if (!((i + 1) % count) || i + 1 == array.length) + Plugin_Scr_AddArray(); + } + Plugin_Scr_FreeArray(&array); +} + +void GScr_LINQ_Contains() +{ + CHECK_PARAMS(2, "Usage: Contains(, )"); + + VariableValueArray array = Plugin_Scr_GetArray(0); + VariableValue element = *Plugin_Scr_SelectParam(1); + qboolean found = qfalse; + + for (int i = 0; i < array.length; i++) + { + VariableValue current = array.items[i]; + + if (current.type == element.type) + { + switch (array.items[i].type) + { + case VAR_VECTOR: + if (current.u.vectorValue[0] == element.u.vectorValue[0] + && current.u.vectorValue[1] == element.u.vectorValue[1] + && current.u.vectorValue[2] == element.u.vectorValue[2]) + break; + continue; + case VAR_INTEGER: + if (current.u.intValue == element.u.intValue) + break; + continue; + case VAR_FLOAT: + if (current.u.floatValue == element.u.floatValue) + break; + continue; + case VAR_ISTRING: + case VAR_STRING: + if (strcmp(Plugin_SL_ConvertToString(current.u.stringValue), + Plugin_SL_ConvertToString(element.u.stringValue)) + == 0) + break; + continue; + case VAR_POINTER: + if (current.u.pointerValue == element.u.pointerValue) + break; + continue; + default: + continue; + } + found = qtrue; + break; + } + } + Plugin_Scr_AddBool(found); +} + +void GScr_LINQ_IndexOf() +{ + CHECK_PARAMS(2, "Usage: IndexOf(, )"); + + VariableValueArray array = Plugin_Scr_GetArray(0); + VariableValue element = *Plugin_Scr_SelectParam(1); + int found = -1; + + for (int i = 0; i < array.length; i++) + { + VariableValue current = array.items[i]; + + if (current.type == element.type) + { + switch (array.items[i].type) + { + case VAR_VECTOR: + if (current.u.vectorValue[0] == element.u.vectorValue[0] + && current.u.vectorValue[1] == element.u.vectorValue[1] + && current.u.vectorValue[2] == element.u.vectorValue[2]) + break; + continue; + case VAR_INTEGER: + if (current.u.intValue == element.u.intValue) + break; + continue; + case VAR_FLOAT: + if (current.u.floatValue == element.u.floatValue) + break; + continue; + case VAR_ISTRING: + case VAR_STRING: + if (strcmp(Plugin_SL_ConvertToString(current.u.stringValue), + Plugin_SL_ConvertToString(element.u.stringValue)) + == 0) + break; + continue; + case VAR_POINTER: + if (current.u.pointerValue == element.u.pointerValue) + break; + continue; + default: + continue; + } + found = i; + break; + } + } + Plugin_Scr_FreeArray(&array); + Plugin_Scr_AddInt(found); +} + +void GScr_LINQ_Remove() +{ + CHECK_PARAMS(2, "Usage: Remove(, )"); + + VariableValueArray array = Plugin_Scr_GetArray(0); + VariableValue element = *Plugin_Scr_SelectParam(1); + + Plugin_Scr_MakeArray(); + for (int i = 0; i < array.length; i++) + { + VariableValue current = array.items[i]; + + if (current.type == element.type) + { + switch (array.items[i].type) + { + case VAR_VECTOR: + if (current.u.vectorValue[0] == element.u.vectorValue[0] + && current.u.vectorValue[1] == element.u.vectorValue[1] + && current.u.vectorValue[2] == element.u.vectorValue[2]) + continue; + break; + case VAR_INTEGER: + if (current.u.intValue == element.u.intValue) + continue; + break; + case VAR_FLOAT: + if (current.u.floatValue == element.u.floatValue) + continue; + break; + case VAR_ISTRING: + case VAR_STRING: + if (strcmp(Plugin_SL_ConvertToString(current.u.stringValue), + Plugin_SL_ConvertToString(element.u.stringValue)) + == 0) + continue; + break; + case VAR_POINTER: + if (current.u.pointerValue == element.u.pointerValue) + continue; + break; + } + } + Plugin_Scr_AddVariable(current); + Plugin_Scr_AddArray(); + } + Plugin_Scr_FreeArray(&array); +} + +void GScr_LINQ_RemoveAt() +{ + CHECK_PARAMS(2, "Usage: RemoveAt(, )"); + + VariableValueArray array = Plugin_Scr_GetArray(0); + int index = Plugin_Scr_GetInt(1); + + Plugin_Scr_MakeArray(); + for (int i = 0; i < array.length; i++) + { + VariableValue current = array.items[i]; + + if (i == index) + continue; + + Plugin_Scr_AddVariable(current); + Plugin_Scr_AddArray(); + } + Plugin_Scr_FreeArray(&array); +} diff --git a/src/net/curl.c b/src/net/curl.c index e2074fb..60ba998 100644 --- a/src/net/curl.c +++ b/src/net/curl.c @@ -1,167 +1,168 @@ -#include "curl.h" -#include - -CURL_HANDLER curl_handler = { 0 }; - -void GScr_CURL_Init() -{ - CHECK_PARAMS(0, "Usage: CURL_Init()"); - - CURL_REQUEST* curl = (CURL_REQUEST*)calloc(1, sizeof(CURL_REQUEST)); - curl->handle = curl_handler.handle; - - CURL_Working(qtrue); - Plugin_Scr_AddInt((int)curl); -} - -void GScr_CURL_Version() -{ - CHECK_PARAMS(0, "Usage: CURL_Version()"); - - curl_version_info_data* info = curl_version_info(CURLVERSION_NOW); - if (!info) return; - - Plugin_Printf("----------[CURL INFO]----------\n"); - Plugin_Printf("Age: %d\nHost: %s\nSSH: %s\nSSL: %s\nVersion: %s\n", - info->age, info->host, info->libssh_version, info->ssl_version, info->version); - - Plugin_Printf("Features: "); - Plugin_Printf("%s", info->features & CURL_VERSION_IPV6 ? "IPv6 " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_SSL ? "SSL " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_LIBZ ? "LIBZ " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_NTLM ? "NTML " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_DEBUG ? "Debug " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_ASYNCHDNS ? "AsyncHDNS " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_SPNEGO ? "SPNEGO " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_LARGEFILE ? "Largefile " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_IDN ? "IDN " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_SSPI ? "SSPI " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_CONV ? "CONV " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_CURLDEBUG ? "CURLDEBUG " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_TLSAUTH_SRP ? "TLSAUTH_SRP " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_NTLM_WB ? "NTLM_WB " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_HTTP2 ? "HTTP2 " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_GSSAPI ? "GSSAPI " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_KERBEROS5 ? "KERBEROS5 " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_UNIX_SOCKETS ? "Unix-Sockets " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_PSL ? "PSL " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_HTTPS_PROXY ? "HTTPS_PROXY " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_MULTI_SSL ? "MULTI_SSL " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_BROTLI ? "BROTLI " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_ALTSVC ? "ALTSVC " : ""); - Plugin_Printf("%s", info->features & CURL_VERSION_HTTP3 ? "HTTP3 " : ""); - Plugin_Printf("\n"); - - Plugin_Printf("Protocols: "); - for (int i = 0; info->protocols[i] != NULL; i++) - Plugin_Printf("%s ", info->protocols[i]); - Plugin_Printf("\n-------------------------------\n"); - - Plugin_Scr_AddString(info->version); -} - -void GScr_CURL_OptCleanup() -{ - CHECK_PARAMS(1, "Usage: CURL_OptCleanup()"); - - CURL_REQUEST* curl = (CURL_REQUEST*)Plugin_Scr_GetInt(0); - CHECK_CURL_REQUEST(curl); - - CURL_OptCleanup(curl); -} - -void GScr_CURL_HeaderCleanup() -{ - CHECK_PARAMS(1, "Usage: CURL_HeaderCleanup()"); - - CURL_REQUEST* curl = (CURL_REQUEST*)Plugin_Scr_GetInt(0); - CHECK_CURL_REQUEST(curl); - - CURL_HeaderCleanup(curl); -} - -void GScr_CURL_AddHeader() -{ - CHECK_PARAMS(2, "Usage: CURL_AddHeader(,
)"); - - CURL_REQUEST* curl = (CURL_REQUEST*)Plugin_Scr_GetInt(0); - CHECK_CURL_REQUEST(curl); - - curl->header = curl_slist_append(curl->header, Plugin_Scr_GetString(1)); -} - -void GScr_CURL_AddOpt() -{ - CHECK_PARAMS(3, "Usage: CURL_AddOpt(, , )"); - - CURL_REQUEST* curl = (CURL_REQUEST*)Plugin_Scr_GetInt(0); - CHECK_CURL_REQUEST(curl); - - curl->opts[curl->optsCount].opt = Plugin_Scr_GetInt(1); - curl->opts[curl->optsCount].param = *Plugin_Scr_SelectParam(2); - curl->optsCount++; -} - -void GScr_CURL_Free() -{ - CHECK_PARAMS(1, "Usage: CURL_Free()"); - - CURL_REQUEST* curl = (CURL_REQUEST*)Plugin_Scr_GetInt(0); - - CHECK_CURL_REQUEST(curl); - - free(curl); - - CURL_Working(qfalse); - Plugin_Scr_AddBool(qtrue); -} - -void CURL_Working(qboolean state) -{ - curl_handler.working = state; -} - -void CURL_SetHeader(CURL_REQUEST *curl, CURLoption headerType) -{ - if (curl->header != NULL) - curl_easy_setopt(curl->handle, headerType, curl->header); -} - -void CURL_OptCleanup(CURL_REQUEST* curl) -{ - curl->optsCount = 0; - memset(&curl->opts, 0, sizeof(curl->opts)); -} - -void CURL_HeaderCleanup(CURL_REQUEST* curl) -{ - if (curl->header != NULL) - { - curl_slist_free_all(curl->header); - curl->header = NULL; - } -} - -void CURL_SetOpts(CURL_REQUEST* curl) -{ - if (curl->optsCount > 0) - { - for (int i = 0; i < curl->optsCount; i++) - { - switch (curl->opts[i].param.type) - { - case VAR_INTEGER: - curl_easy_setopt(curl->handle, curl->opts[i].opt, curl->opts[i].param.u.intValue); - break; - case VAR_FLOAT: - curl_easy_setopt(curl->handle, curl->opts[i].opt, curl->opts[i].param.u.floatValue); - break; - case VAR_ISTRING: - case VAR_STRING: - curl_easy_setopt(curl->handle, curl->opts[i].opt, - Plugin_SL_ConvertToString(curl->opts[i].param.u.stringValue)); - break; - } - } - } -} +#include "curl.h" +#include + +CURL_HANDLER curl_handler = { 0 }; + +void GScr_CURL_Init() +{ + CHECK_PARAMS(0, "Usage: CURL_Init()"); + + CURL_REQUEST* curl = (CURL_REQUEST*)calloc(1, sizeof(CURL_REQUEST)); + curl->handle = curl_handler.handle; + + CURL_Working(qtrue); + Plugin_Scr_AddInt((int)curl); +} + +void GScr_CURL_Version() +{ + CHECK_PARAMS(0, "Usage: CURL_Version()"); + + curl_version_info_data* info = curl_version_info(CURLVERSION_NOW); + if (!info) + return; + + Plugin_Printf("----------[CURL INFO]----------\n"); + Plugin_Printf("Age: %d\nHost: %s\nSSH: %s\nSSL: %s\nVersion: %s\n", info->age, info->host, info->libssh_version, + info->ssl_version, info->version); + + Plugin_Printf("Features: "); + Plugin_Printf("%s", info->features & CURL_VERSION_IPV6 ? "IPv6 " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_SSL ? "SSL " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_LIBZ ? "LIBZ " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_NTLM ? "NTML " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_DEBUG ? "Debug " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_ASYNCHDNS ? "AsyncHDNS " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_SPNEGO ? "SPNEGO " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_LARGEFILE ? "Largefile " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_IDN ? "IDN " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_SSPI ? "SSPI " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_CONV ? "CONV " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_CURLDEBUG ? "CURLDEBUG " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_TLSAUTH_SRP ? "TLSAUTH_SRP " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_NTLM_WB ? "NTLM_WB " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_HTTP2 ? "HTTP2 " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_GSSAPI ? "GSSAPI " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_KERBEROS5 ? "KERBEROS5 " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_UNIX_SOCKETS ? "Unix-Sockets " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_PSL ? "PSL " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_HTTPS_PROXY ? "HTTPS_PROXY " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_MULTI_SSL ? "MULTI_SSL " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_BROTLI ? "BROTLI " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_ALTSVC ? "ALTSVC " : ""); + Plugin_Printf("%s", info->features & CURL_VERSION_HTTP3 ? "HTTP3 " : ""); + Plugin_Printf("\n"); + + Plugin_Printf("Protocols: "); + for (int i = 0; info->protocols[i] != NULL; i++) + Plugin_Printf("%s ", info->protocols[i]); + Plugin_Printf("\n-------------------------------\n"); + + Plugin_Scr_AddString(info->version); +} + +void GScr_CURL_OptCleanup() +{ + CHECK_PARAMS(1, "Usage: CURL_OptCleanup()"); + + CURL_REQUEST* curl = (CURL_REQUEST*)Plugin_Scr_GetInt(0); + CHECK_CURL_REQUEST(curl); + + CURL_OptCleanup(curl); +} + +void GScr_CURL_HeaderCleanup() +{ + CHECK_PARAMS(1, "Usage: CURL_HeaderCleanup()"); + + CURL_REQUEST* curl = (CURL_REQUEST*)Plugin_Scr_GetInt(0); + CHECK_CURL_REQUEST(curl); + + CURL_HeaderCleanup(curl); +} + +void GScr_CURL_AddHeader() +{ + CHECK_PARAMS(2, "Usage: CURL_AddHeader(,
)"); + + CURL_REQUEST* curl = (CURL_REQUEST*)Plugin_Scr_GetInt(0); + CHECK_CURL_REQUEST(curl); + + curl->header = curl_slist_append(curl->header, Plugin_Scr_GetString(1)); +} + +void GScr_CURL_AddOpt() +{ + CHECK_PARAMS(3, "Usage: CURL_AddOpt(, , )"); + + CURL_REQUEST* curl = (CURL_REQUEST*)Plugin_Scr_GetInt(0); + CHECK_CURL_REQUEST(curl); + + curl->opts[curl->optsCount].opt = Plugin_Scr_GetInt(1); + curl->opts[curl->optsCount].param = *Plugin_Scr_SelectParam(2); + curl->optsCount++; +} + +void GScr_CURL_Free() +{ + CHECK_PARAMS(1, "Usage: CURL_Free()"); + + CURL_REQUEST* curl = (CURL_REQUEST*)Plugin_Scr_GetInt(0); + + CHECK_CURL_REQUEST(curl); + + free(curl); + + CURL_Working(qfalse); + Plugin_Scr_AddBool(qtrue); +} + +void CURL_Working(qboolean state) +{ + curl_handler.working = state; +} + +void CURL_SetHeader(CURL_REQUEST* curl, CURLoption headerType) +{ + if (curl->header != NULL) + curl_easy_setopt(curl->handle, headerType, curl->header); +} + +void CURL_OptCleanup(CURL_REQUEST* curl) +{ + curl->optsCount = 0; + memset(&curl->opts, 0, sizeof(curl->opts)); +} + +void CURL_HeaderCleanup(CURL_REQUEST* curl) +{ + if (curl->header != NULL) + { + curl_slist_free_all(curl->header); + curl->header = NULL; + } +} + +void CURL_SetOpts(CURL_REQUEST* curl) +{ + if (curl->optsCount > 0) + { + for (int i = 0; i < curl->optsCount; i++) + { + switch (curl->opts[i].param.type) + { + case VAR_INTEGER: + curl_easy_setopt(curl->handle, curl->opts[i].opt, curl->opts[i].param.u.intValue); + break; + case VAR_FLOAT: + curl_easy_setopt(curl->handle, curl->opts[i].opt, curl->opts[i].param.u.floatValue); + break; + case VAR_ISTRING: + case VAR_STRING: + curl_easy_setopt(curl->handle, curl->opts[i].opt, + Plugin_SL_ConvertToString(curl->opts[i].param.u.stringValue)); + break; + } + } + } +} diff --git a/src/net/curl.h b/src/net/curl.h index b90c516..2bccda3 100644 --- a/src/net/curl.h +++ b/src/net/curl.h @@ -1,113 +1,112 @@ -#pragma once -#include -#include - -#include "sys/system.h" -#include "data/file.h" - -#include - -#define CURL_CHECK_ERROR(x, msg) \ -if (x) \ -{ \ - Plugin_Scr_Error(msg); \ - return; \ -} - -#define CHECK_CURL_REQUEST(curl) \ -CURL_CHECK_ERROR(!curl, "CURL request not found."); \ -CURL_CHECK_ERROR(curl->worker && curl->worker->status == ASYNC_PENDING, "CURL request is pending."); - -#define CHECK_CURL_WORKING() \ -CURL_CHECK_ERROR(curl_handler.working, "CURL is processing another request."); - -typedef struct -{ - CURLcode code; - CURL* handle; - qboolean working; -} CURL_HANDLER; - -typedef struct -{ - long opt; - VariableValue param; -} CURL_OPTS; - -typedef struct -{ - async_worker* worker; - CURL* handle; - CURLM* multiHandle; - struct curl_slist* header; - int optsCount; - CURL_OPTS opts[512]; -} CURL_REQUEST; - -extern CURL_HANDLER curl_handler; - -/// -/// Init a new CURL request. -/// -void GScr_CURL_Init(); - -/// -/// Print info about curl library. -/// -void GScr_CURL_Version(); - -/// -/// Add a CURL Header for the next requests. -/// -void GScr_CURL_AddHeader(); - -/// -/// Clean header set by CURL_AddHeader. -/// -void GScr_CURL_HeaderCleanup(); - -/// -/// Clean all CURL Option added by CURL_AddOpt. -/// -void GScr_CURL_OptCleanup(); - -/// -/// Add a CURL Option for the next request. -/// -void GScr_CURL_AddOpt(); - -/// -/// Free a CURL request. -/// -void GScr_CURL_Free(); - -/// -/// Set the CURL working state. -/// -/// The working state. -void CURL_Working(qboolean state); - -/// -/// Set the options that has been set in the CURL_REQUEST struct. -/// -/// The CURL request. -void CURL_SetOpts(CURL_REQUEST* curl); - -/// -/// Set the header that has been set in the CURL_REQUEST struct. -/// -/// The CURL request. -/// The header option type. -void CURL_SetHeader(CURL_REQUEST* curl, CURLoption header_type); - -/// -/// Cleanup all CURL options from the CURL_REQUEST struct. -/// -/// The CURL request. -void CURL_OptCleanup(CURL_REQUEST* curl); - -/// -/// Cleanup the CURL header from the CURL_REQUEST struct. -/// -/// The CURL request. -void CURL_HeaderCleanup(CURL_REQUEST* curl); +#pragma once +#include +#include + +#include "data/file.h" +#include "sys/system.h" + +#include + +#define CURL_CHECK_ERROR(x, msg) \ + if (x) \ + { \ + Plugin_Scr_Error(msg); \ + return; \ + } + +#define CHECK_CURL_REQUEST(curl) \ + CURL_CHECK_ERROR(!curl, "CURL request not found."); \ + CURL_CHECK_ERROR(curl->worker && curl->worker->status == ASYNC_PENDING, "CURL request is pending."); + +#define CHECK_CURL_WORKING() CURL_CHECK_ERROR(curl_handler.working, "CURL is processing another request."); + +typedef struct +{ + CURLcode code; + CURL* handle; + qboolean working; +} CURL_HANDLER; + +typedef struct +{ + long opt; + VariableValue param; +} CURL_OPTS; + +typedef struct +{ + async_worker* worker; + CURL* handle; + CURLM* multiHandle; + struct curl_slist* header; + int optsCount; + CURL_OPTS opts[512]; +} CURL_REQUEST; + +extern CURL_HANDLER curl_handler; + +/// +/// Init a new CURL request. +/// +void GScr_CURL_Init(); + +/// +/// Print info about curl library. +/// +void GScr_CURL_Version(); + +/// +/// Add a CURL Header for the next requests. +/// +void GScr_CURL_AddHeader(); + +/// +/// Clean header set by CURL_AddHeader. +/// +void GScr_CURL_HeaderCleanup(); + +/// +/// Clean all CURL Option added by CURL_AddOpt. +/// +void GScr_CURL_OptCleanup(); + +/// +/// Add a CURL Option for the next request. +/// +void GScr_CURL_AddOpt(); + +/// +/// Free a CURL request. +/// +void GScr_CURL_Free(); + +/// +/// Set the CURL working state. +/// +/// The working state. +void CURL_Working(qboolean state); + +/// +/// Set the options that has been set in the CURL_REQUEST struct. +/// +/// The CURL request. +void CURL_SetOpts(CURL_REQUEST* curl); + +/// +/// Set the header that has been set in the CURL_REQUEST struct. +/// +/// The CURL request. +/// The header option type. +void CURL_SetHeader(CURL_REQUEST* curl, CURLoption header_type); + +/// +/// Cleanup all CURL options from the CURL_REQUEST struct. +/// +/// The CURL request. +void CURL_OptCleanup(CURL_REQUEST* curl); + +/// +/// Cleanup the CURL header from the CURL_REQUEST struct. +/// +/// The CURL request. +void CURL_HeaderCleanup(CURL_REQUEST* curl); diff --git a/src/net/ftp.c b/src/net/ftp.c index b43938f..2239bc7 100644 --- a/src/net/ftp.c +++ b/src/net/ftp.c @@ -1,254 +1,253 @@ -#include "ftp.h" - -#include -#include - -FTP_HANDLER ftp_handler = { 0 }; - -void GScr_FTP_Init() -{ - CHECK_PARAMS(0, "Usage: FTP_Init()"); - - FTP_REQUEST* ftp = (FTP_REQUEST*)calloc(1, sizeof(FTP_REQUEST)); - ftp->curl.handle = ftp_handler.handle; - ftp->curl.multiHandle = ftp_handler.multiHandle; - curl_multi_add_handle(ftp->curl.multiHandle, ftp->curl.handle); - - FTP_Working(qtrue); - Plugin_Scr_AddInt((int)ftp); -} - -void GScr_SFTP_Connect() -{ - CHECK_PARAMS(4, "Usage: SFTP_Connect(, , , )"); - - qboolean connect = FTP_Connect("sftp", Plugin_Scr_GetString(0), Plugin_Scr_GetString(1), - Plugin_Scr_GetString(2), Plugin_Scr_GetInt(3)); - - Plugin_Scr_AddBool(connect); -} - -void GScr_FTP_Connect() -{ - CHECK_PARAMS(4, "Usage: FTP_Connect(, , , )"); - - qboolean connect = FTP_Connect("ftp", Plugin_Scr_GetString(0), Plugin_Scr_GetString(1), - Plugin_Scr_GetString(2), Plugin_Scr_GetInt(3)); - - Plugin_Scr_AddBool(connect); -} - -void GScr_FTP_Close() -{ - CHECK_PARAMS(0, "Usage: FTP_Close()"); - Plugin_Scr_AddBool(FTP_Close()); -} - -void GScr_FTP_Shell() -{ - CHECK_PARAMS(1, "Usage: FTP_Shell()"); - - FTP_REQUEST* ftp = (FTP_REQUEST*)Plugin_Scr_GetInt(0); - - CHECK_FTP_REQUEST(ftp); - CHECK_FTP_INSTANCE(ftp->curl.handle); - - if (ftp->curl.handle) - { - curl_easy_reset(ftp->curl.handle); - - CURL_SetHeader(&ftp->curl, CURLOPT_QUOTE); - curl_easy_setopt(ftp->curl.handle, CURLOPT_URL, ftp_handler.url); - curl_easy_setopt(ftp->curl.handle, CURLOPT_PASSWORD, ftp_handler.password); - curl_easy_setopt(ftp->curl.handle, CURLOPT_PORT, ftp_handler.port); - curl_easy_setopt(ftp->curl.handle, CURLOPT_SSH_AUTH_TYPES, CURLSSH_AUTH_PASSWORD); - CURL_SetOpts(&ftp->curl); - - ftp->curl.worker = Plugin_AsyncWorker(asyncHandler, ftp, &FTP_Execute, NULL); - } - Plugin_Scr_AddBool(qtrue); -} - -void GScr_FTP_PostFile() -{ - CHECK_PARAMS(3, "Usage: FTP_PostFile(, , )"); - - FTP_REQUEST* ftp = (FTP_REQUEST*)Plugin_Scr_GetInt(0); - - CHECK_FTP_REQUEST(ftp); - CHECK_FTP_INSTANCE(ftp->curl.handle); - - const char *filepath = Plugin_Scr_GetString(1); - struct stat file_info; - curl_off_t fsize; - - // Check file - if (stat(filepath, &file_info)) - { - Plugin_Printf("Couldn't open '%s': %s\n", filepath, strerror(errno)); - Plugin_Scr_AddBool(qfalse); - ftp->curl.worker->status = ASYNC_FAILURE; - return; - } - fsize = (curl_off_t)file_info.st_size; - - strcpy((char*)ftp->file.filename, filepath); - ftp->file.stream = fopen(filepath, "rb"); - - if (!ftp->file.stream) - { - Plugin_Printf("File not found.\n"); - Plugin_Scr_AddBool(qfalse); - ftp->curl.worker->status = ASYNC_FAILURE; - return; - } - - // Post file - if (ftp->curl.handle) - { - curl_easy_reset(ftp->curl.handle); - - char url[4096]; - strcpy(url, ftp_handler.url); - strcat(url, Plugin_Scr_GetString(2)); - - CURL_SetHeader(&ftp->curl, CURLOPT_POSTQUOTE); - curl_easy_setopt(ftp->curl.handle, CURLOPT_URL, url); - curl_easy_setopt(ftp->curl.handle, CURLOPT_PASSWORD, ftp_handler.password); - curl_easy_setopt(ftp->curl.handle, CURLOPT_PORT, ftp_handler.port); - curl_easy_setopt(ftp->curl.handle, CURLOPT_READFUNCTION, FTP_Read); - curl_easy_setopt(ftp->curl.handle, CURLOPT_UPLOAD, 1L); - curl_easy_setopt(ftp->curl.handle, CURLOPT_READDATA, ftp->file.stream); - curl_easy_setopt(ftp->curl.handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fsize); - curl_easy_setopt(ftp->curl.handle, CURLOPT_SSH_AUTH_TYPES, CURLSSH_AUTH_PASSWORD); - CURL_SetOpts(&ftp->curl); - - ftp->curl.worker = Plugin_AsyncWorker(asyncHandler, ftp, &FTP_Execute, NULL); - } - Plugin_Scr_AddBool(qtrue); -} - -void GScr_FTP_GetFile() -{ - CHECK_PARAMS(3, "Usage: FTP_GetFile(, , )"); - - FTP_REQUEST* ftp = (FTP_REQUEST*)Plugin_Scr_GetInt(0); - - CHECK_FTP_REQUEST(ftp); - CHECK_FTP_INSTANCE(ftp->curl.handle); - - const char *filepath = Plugin_Scr_GetString(1); - strcpy((char*)ftp->file.filename, filepath); - - if (ftp->curl.handle) - { - curl_easy_reset(ftp->curl.handle); - - char url[4096]; - strcpy(url, ftp_handler.url); - strcat(url, Plugin_Scr_GetString(2)); - - CURL_SetHeader(&ftp->curl, CURLOPT_PREQUOTE); - curl_easy_setopt(ftp->curl.handle, CURLOPT_URL, url); - curl_easy_setopt(ftp->curl.handle, CURLOPT_PASSWORD, ftp_handler.password); - curl_easy_setopt(ftp->curl.handle, CURLOPT_PORT, ftp_handler.port); - curl_easy_setopt(ftp->curl.handle, CURLOPT_WRITEFUNCTION, FTP_Write); - curl_easy_setopt(ftp->curl.handle, CURLOPT_WRITEDATA, ftp->file.stream); - curl_easy_setopt(ftp->curl.handle, CURLOPT_SSH_AUTH_TYPES, CURLSSH_AUTH_PASSWORD); - CURL_SetOpts(&ftp->curl); - - ftp->curl.worker = Plugin_AsyncWorker(asyncHandler, ftp, &FTP_Execute, NULL); - } - Plugin_Scr_AddBool(qtrue); -} - -void GScr_FTP_Free() -{ - CHECK_PARAMS(1, "Usage: FTP_Free()"); - - FTP_REQUEST* ftp = (FTP_REQUEST*)Plugin_Scr_GetInt(0); - - CHECK_FTP_REQUEST(ftp); - - CURL_OptCleanup(&ftp->curl); - CURL_HeaderCleanup(&ftp->curl); - - if (ftp->file.stream) - fclose(ftp->file.stream); - free(ftp); - - FTP_Working(qfalse); - Plugin_Scr_AddBool(qtrue); -} - -qboolean FTP_Close() -{ - if (ftp_handler.handle != NULL) - { - if (ftp_handler.multiHandle) - { - curl_multi_remove_handle(ftp_handler.multiHandle, ftp_handler.handle); - curl_multi_cleanup(ftp_handler.multiHandle); - } - curl_easy_cleanup(ftp_handler.handle); - memset(&ftp_handler, 0, sizeof(ftp_handler)); - return qtrue; - } - return qfalse; -} - -qboolean FTP_Connect(const char* protocol, const char* hostname, const char* username, - const char* password, unsigned short port) -{ - FTP_Close(); - - snprintf(ftp_handler.url, sizeof(ftp_handler.url), "%s://%s@%s/", protocol, username, hostname); - strcpy(ftp_handler.password, password); - ftp_handler.port = port; - ftp_handler.handle = curl_easy_init(); - ftp_handler.multiHandle = curl_multi_init(); - return ftp_handler.handle != NULL; -} - -size_t FTP_Write(void* buffer, size_t size, size_t nmemb, void* stream) -{ - FTP_FILE* out = (FTP_FILE*)stream; - if (!out->stream) - { - out->stream = fopen(out->filename, "wb"); - if (!out->stream) - return -1; - } - return fwrite(buffer, size, nmemb, out->stream); -} - -size_t FTP_Read(void* ptr, size_t size, size_t nmemb, void* stream) -{ - return (curl_off_t)fread(ptr, size, nmemb, (FILE*)stream); -} - -void FTP_Working(qboolean state) -{ - ftp_handler.working = state; -} - -void FTP_Execute(uv_work_t* req) -{ - async_worker* worker = (async_worker*)req->data; - FTP_REQUEST* ftp = (FTP_REQUEST*)worker->data; - int running = 0; - - do - { - const CURLMcode res = curl_multi_perform(ftp->curl.multiHandle, &running); - if (res != CURLM_OK) - { - Sys_PrintF("curl_multi_perform() failed: %s\n", curl_multi_strerror(res)); - Plugin_AsyncWorkerDone(req, ASYNC_FAILURE); - return; - } - } - while (running && worker->status != ASYNC_CANCEL); - - Plugin_AsyncWorkerDone(req, ASYNC_SUCCESSFUL); -} +#include "ftp.h" + +#include +#include + +FTP_HANDLER ftp_handler = { 0 }; + +void GScr_FTP_Init() +{ + CHECK_PARAMS(0, "Usage: FTP_Init()"); + + FTP_REQUEST* ftp = (FTP_REQUEST*)calloc(1, sizeof(FTP_REQUEST)); + ftp->curl.handle = ftp_handler.handle; + ftp->curl.multiHandle = ftp_handler.multiHandle; + curl_multi_add_handle(ftp->curl.multiHandle, ftp->curl.handle); + + FTP_Working(qtrue); + Plugin_Scr_AddInt((int)ftp); +} + +void GScr_SFTP_Connect() +{ + CHECK_PARAMS(4, "Usage: SFTP_Connect(, , , )"); + + qboolean connect = FTP_Connect("sftp", Plugin_Scr_GetString(0), Plugin_Scr_GetString(1), Plugin_Scr_GetString(2), + Plugin_Scr_GetInt(3)); + + Plugin_Scr_AddBool(connect); +} + +void GScr_FTP_Connect() +{ + CHECK_PARAMS(4, "Usage: FTP_Connect(, , , )"); + + qboolean connect = FTP_Connect("ftp", Plugin_Scr_GetString(0), Plugin_Scr_GetString(1), Plugin_Scr_GetString(2), + Plugin_Scr_GetInt(3)); + + Plugin_Scr_AddBool(connect); +} + +void GScr_FTP_Close() +{ + CHECK_PARAMS(0, "Usage: FTP_Close()"); + Plugin_Scr_AddBool(FTP_Close()); +} + +void GScr_FTP_Shell() +{ + CHECK_PARAMS(1, "Usage: FTP_Shell()"); + + FTP_REQUEST* ftp = (FTP_REQUEST*)Plugin_Scr_GetInt(0); + + CHECK_FTP_REQUEST(ftp); + CHECK_FTP_INSTANCE(ftp->curl.handle); + + if (ftp->curl.handle) + { + curl_easy_reset(ftp->curl.handle); + + CURL_SetHeader(&ftp->curl, CURLOPT_QUOTE); + curl_easy_setopt(ftp->curl.handle, CURLOPT_URL, ftp_handler.url); + curl_easy_setopt(ftp->curl.handle, CURLOPT_PASSWORD, ftp_handler.password); + curl_easy_setopt(ftp->curl.handle, CURLOPT_PORT, ftp_handler.port); + curl_easy_setopt(ftp->curl.handle, CURLOPT_SSH_AUTH_TYPES, CURLSSH_AUTH_PASSWORD); + CURL_SetOpts(&ftp->curl); + + ftp->curl.worker = Plugin_AsyncWorker(asyncHandler, ftp, &FTP_Execute, NULL); + } + Plugin_Scr_AddBool(qtrue); +} + +void GScr_FTP_PostFile() +{ + CHECK_PARAMS(3, "Usage: FTP_PostFile(, , )"); + + FTP_REQUEST* ftp = (FTP_REQUEST*)Plugin_Scr_GetInt(0); + + CHECK_FTP_REQUEST(ftp); + CHECK_FTP_INSTANCE(ftp->curl.handle); + + const char* filepath = Plugin_Scr_GetString(1); + struct stat file_info; + curl_off_t fsize; + + // Check file + if (stat(filepath, &file_info)) + { + Plugin_Printf("Couldn't open '%s': %s\n", filepath, strerror(errno)); + Plugin_Scr_AddBool(qfalse); + ftp->curl.worker->status = ASYNC_FAILURE; + return; + } + fsize = (curl_off_t)file_info.st_size; + + strcpy((char*)ftp->file.filename, filepath); + ftp->file.stream = fopen(filepath, "rb"); + + if (!ftp->file.stream) + { + Plugin_Printf("File not found.\n"); + Plugin_Scr_AddBool(qfalse); + ftp->curl.worker->status = ASYNC_FAILURE; + return; + } + + // Post file + if (ftp->curl.handle) + { + curl_easy_reset(ftp->curl.handle); + + char url[4096]; + strcpy(url, ftp_handler.url); + strcat(url, Plugin_Scr_GetString(2)); + + CURL_SetHeader(&ftp->curl, CURLOPT_POSTQUOTE); + curl_easy_setopt(ftp->curl.handle, CURLOPT_URL, url); + curl_easy_setopt(ftp->curl.handle, CURLOPT_PASSWORD, ftp_handler.password); + curl_easy_setopt(ftp->curl.handle, CURLOPT_PORT, ftp_handler.port); + curl_easy_setopt(ftp->curl.handle, CURLOPT_READFUNCTION, FTP_Read); + curl_easy_setopt(ftp->curl.handle, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(ftp->curl.handle, CURLOPT_READDATA, ftp->file.stream); + curl_easy_setopt(ftp->curl.handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fsize); + curl_easy_setopt(ftp->curl.handle, CURLOPT_SSH_AUTH_TYPES, CURLSSH_AUTH_PASSWORD); + CURL_SetOpts(&ftp->curl); + + ftp->curl.worker = Plugin_AsyncWorker(asyncHandler, ftp, &FTP_Execute, NULL); + } + Plugin_Scr_AddBool(qtrue); +} + +void GScr_FTP_GetFile() +{ + CHECK_PARAMS(3, "Usage: FTP_GetFile(, , )"); + + FTP_REQUEST* ftp = (FTP_REQUEST*)Plugin_Scr_GetInt(0); + + CHECK_FTP_REQUEST(ftp); + CHECK_FTP_INSTANCE(ftp->curl.handle); + + const char* filepath = Plugin_Scr_GetString(1); + strcpy((char*)ftp->file.filename, filepath); + + if (ftp->curl.handle) + { + curl_easy_reset(ftp->curl.handle); + + char url[4096]; + strcpy(url, ftp_handler.url); + strcat(url, Plugin_Scr_GetString(2)); + + CURL_SetHeader(&ftp->curl, CURLOPT_PREQUOTE); + curl_easy_setopt(ftp->curl.handle, CURLOPT_URL, url); + curl_easy_setopt(ftp->curl.handle, CURLOPT_PASSWORD, ftp_handler.password); + curl_easy_setopt(ftp->curl.handle, CURLOPT_PORT, ftp_handler.port); + curl_easy_setopt(ftp->curl.handle, CURLOPT_WRITEFUNCTION, FTP_Write); + curl_easy_setopt(ftp->curl.handle, CURLOPT_WRITEDATA, ftp->file.stream); + curl_easy_setopt(ftp->curl.handle, CURLOPT_SSH_AUTH_TYPES, CURLSSH_AUTH_PASSWORD); + CURL_SetOpts(&ftp->curl); + + ftp->curl.worker = Plugin_AsyncWorker(asyncHandler, ftp, &FTP_Execute, NULL); + } + Plugin_Scr_AddBool(qtrue); +} + +void GScr_FTP_Free() +{ + CHECK_PARAMS(1, "Usage: FTP_Free()"); + + FTP_REQUEST* ftp = (FTP_REQUEST*)Plugin_Scr_GetInt(0); + + CHECK_FTP_REQUEST(ftp); + + CURL_OptCleanup(&ftp->curl); + CURL_HeaderCleanup(&ftp->curl); + + if (ftp->file.stream) + fclose(ftp->file.stream); + free(ftp); + + FTP_Working(qfalse); + Plugin_Scr_AddBool(qtrue); +} + +qboolean FTP_Close() +{ + if (ftp_handler.handle != NULL) + { + if (ftp_handler.multiHandle) + { + curl_multi_remove_handle(ftp_handler.multiHandle, ftp_handler.handle); + curl_multi_cleanup(ftp_handler.multiHandle); + } + curl_easy_cleanup(ftp_handler.handle); + memset(&ftp_handler, 0, sizeof(ftp_handler)); + return qtrue; + } + return qfalse; +} + +qboolean FTP_Connect(const char* protocol, const char* hostname, const char* username, const char* password, + unsigned short port) +{ + FTP_Close(); + + snprintf(ftp_handler.url, sizeof(ftp_handler.url), "%s://%s@%s/", protocol, username, hostname); + strcpy(ftp_handler.password, password); + ftp_handler.port = port; + ftp_handler.handle = curl_easy_init(); + ftp_handler.multiHandle = curl_multi_init(); + return ftp_handler.handle != NULL; +} + +size_t FTP_Write(void* buffer, size_t size, size_t nmemb, void* stream) +{ + FTP_FILE* out = (FTP_FILE*)stream; + if (!out->stream) + { + out->stream = fopen(out->filename, "wb"); + if (!out->stream) + return -1; + } + return fwrite(buffer, size, nmemb, out->stream); +} + +size_t FTP_Read(void* ptr, size_t size, size_t nmemb, void* stream) +{ + return (curl_off_t)fread(ptr, size, nmemb, (FILE*)stream); +} + +void FTP_Working(qboolean state) +{ + ftp_handler.working = state; +} + +void FTP_Execute(uv_work_t* req) +{ + async_worker* worker = (async_worker*)req->data; + FTP_REQUEST* ftp = (FTP_REQUEST*)worker->data; + int running = 0; + + do + { + const CURLMcode res = curl_multi_perform(ftp->curl.multiHandle, &running); + if (res != CURLM_OK) + { + Sys_PrintF("curl_multi_perform() failed: %s\n", curl_multi_strerror(res)); + Plugin_AsyncWorkerDone(req, ASYNC_FAILURE); + return; + } + } while (running && worker->status != ASYNC_CANCEL); + + Plugin_AsyncWorkerDone(req, ASYNC_SUCCESSFUL); +} diff --git a/src/net/ftp.h b/src/net/ftp.h index 3c4175b..6c5267e 100644 --- a/src/net/ftp.h +++ b/src/net/ftp.h @@ -1,117 +1,116 @@ -#pragma once -#include "curl.h" -#include - -#define CHECK_FTP_REQUEST(ftp) \ -CURL_CHECK_ERROR(!ftp, "FTP request not found."); \ -CURL_CHECK_ERROR(ftp->curl.worker && ftp->curl.worker->status == ASYNC_PENDING, "FTP request is pending."); - -#define CHECK_FTP_INSTANCE(handle) \ -CURL_CHECK_ERROR(!handle, "FTP Connection not found.\n"); - -typedef struct -{ - const char filename[MAX_PATH]; - FILE* stream; -} FTP_FILE; - -typedef struct -{ - CURL* handle; - CURLM* multiHandle; - char url[4096]; - char password[255]; - unsigned short port; - qboolean working; -} FTP_HANDLER; - -typedef struct -{ - CURL_REQUEST curl; - FTP_FILE file; -} FTP_REQUEST; - -extern FTP_HANDLER ftp_handler; - -/// -/// Init the FTP request. -/// -void GScr_FTP_Init(); - -/// -/// Connect to an SFTP server, the connection can be closed with FTP_Close. -/// -void GScr_SFTP_Connect(); - -/// -/// Connect to an FTP/FTPS server, the connection can be closed with FTP_Close. -/// -void GScr_FTP_Connect(); - -/// -/// Close the FTP/FTPS/SFTP connection. -/// -void GScr_FTP_Close(); - -/// -/// Execute a command to the FTP/FTPS/SFTP server. -/// The commands should be set with CURL_AddHeader. -/// -void GScr_FTP_Shell(); - -/// -/// Upload a file to the FTP/FTPS/SFTP server. -/// -void GScr_FTP_PostFile(); - -/// -/// Download a file from the FTP/FTPS/SFTP server. -/// -void GScr_FTP_GetFile(); - -/// -/// Free an FTP request. -/// -void GScr_FTP_Free(); - -/// -/// Connect to a FTP/FTPS/SFTP server. -/// -/// File protocol to use i.e: FTP/SFTP. -/// Host ip/name address. -/// The username to connect with. -/// The password to connect with. -/// The server port. -/// True when the connection succeded. -qboolean FTP_Connect(const char* protocol, const char* hostname, const char* username, - const char* password, unsigned short port); - -/// -/// Close all connections. -/// -/// -qboolean FTP_Close(); - -/// -/// File write function to use with ftp CURL write callback. -/// -/// -size_t FTP_Write(void* buffer, size_t size, size_t nmemb, void* stream); - -/// -/// File read function to use with ftp CURL read callback. -/// -/// -size_t FTP_Read(void* ptr, size_t size, size_t nmemb, void* stream); - -/// -/// Set the FTP working state. -/// -/// The working state. -void FTP_Working(qboolean state); - -/// -/// Execute the async request. -/// -/// The worker request. -void FTP_Execute(uv_work_t * req); +#pragma once +#include +#include "curl.h" + +#define CHECK_FTP_REQUEST(ftp) \ + CURL_CHECK_ERROR(!ftp, "FTP request not found."); \ + CURL_CHECK_ERROR(ftp->curl.worker && ftp->curl.worker->status == ASYNC_PENDING, "FTP request is pending."); + +#define CHECK_FTP_INSTANCE(handle) CURL_CHECK_ERROR(!handle, "FTP Connection not found.\n"); + +typedef struct +{ + const char filename[MAX_PATH]; + FILE* stream; +} FTP_FILE; + +typedef struct +{ + CURL* handle; + CURLM* multiHandle; + char url[4096]; + char password[255]; + unsigned short port; + qboolean working; +} FTP_HANDLER; + +typedef struct +{ + CURL_REQUEST curl; + FTP_FILE file; +} FTP_REQUEST; + +extern FTP_HANDLER ftp_handler; + +/// +/// Init the FTP request. +/// +void GScr_FTP_Init(); + +/// +/// Connect to an SFTP server, the connection can be closed with FTP_Close. +/// +void GScr_SFTP_Connect(); + +/// +/// Connect to an FTP/FTPS server, the connection can be closed with FTP_Close. +/// +void GScr_FTP_Connect(); + +/// +/// Close the FTP/FTPS/SFTP connection. +/// +void GScr_FTP_Close(); + +/// +/// Execute a command to the FTP/FTPS/SFTP server. +/// The commands should be set with CURL_AddHeader. +/// +void GScr_FTP_Shell(); + +/// +/// Upload a file to the FTP/FTPS/SFTP server. +/// +void GScr_FTP_PostFile(); + +/// +/// Download a file from the FTP/FTPS/SFTP server. +/// +void GScr_FTP_GetFile(); + +/// +/// Free an FTP request. +/// +void GScr_FTP_Free(); + +/// +/// Connect to a FTP/FTPS/SFTP server. +/// +/// File protocol to use i.e: FTP/SFTP. +/// Host ip/name address. +/// The username to connect with. +/// The password to connect with. +/// The server port. +/// True when the connection succeded. +qboolean FTP_Connect(const char* protocol, const char* hostname, const char* username, const char* password, + unsigned short port); + +/// +/// Close all connections. +/// +/// +qboolean FTP_Close(); + +/// +/// File write function to use with ftp CURL write callback. +/// +/// +size_t FTP_Write(void* buffer, size_t size, size_t nmemb, void* stream); + +/// +/// File read function to use with ftp CURL read callback. +/// +/// +size_t FTP_Read(void* ptr, size_t size, size_t nmemb, void* stream); + +/// +/// Set the FTP working state. +/// +/// The working state. +void FTP_Working(qboolean state); + +/// +/// Execute the async request. +/// +/// The worker request. +void FTP_Execute(uv_work_t* req); diff --git a/src/net/http.c b/src/net/http.c index aab8874..0da1032 100644 --- a/src/net/http.c +++ b/src/net/http.c @@ -1,240 +1,239 @@ -#include "http.h" - -#include -#include - -HTTP_HANDLER http_handler = { 0 }; - -void GScr_HTTP_Init() -{ - CHECK_PARAMS(0, "Usage: HTTP_Init()"); - - HTTP_REQUEST* http = (HTTP_REQUEST*)calloc(1, sizeof(HTTP_REQUEST)); - http->curl.handle = curl_easy_init(); - http->curl.multiHandle = curl_multi_init(); - curl_multi_add_handle(http->curl.multiHandle, http->curl.handle); - - HTTP_Working(qtrue); - Plugin_Scr_AddInt((int)http); -} - -void GScr_HTTP_Free() -{ - CHECK_PARAMS(1, "Usage: HTTP_Free()"); - - HTTP_REQUEST* http = (HTTP_REQUEST*)Plugin_Scr_GetInt(0); - - CHECK_HTTP_REQUEST(http); - - CURL_OptCleanup(&http->curl); - CURL_HeaderCleanup(&http->curl); - - if (http->curl.multiHandle) - { - curl_multi_remove_handle(http->curl.multiHandle, http->curl.handle); - curl_multi_cleanup(http->curl.multiHandle); - } - if (http->curl.handle) - curl_easy_cleanup(http->curl.handle); - if (http->response.buffer) - free(http->response.buffer); - if (http->file.stream) - fclose(http->file.stream); - free(http); - - HTTP_Working(qfalse); - Plugin_Scr_AddBool(qtrue); -} - -void GScr_HTTP_Get() -{ - CHECK_PARAMS(2, "Usage: HTTP_GetString(, )"); - - HTTP_REQUEST* http = (HTTP_REQUEST*)Plugin_Scr_GetInt(0); - - CHECK_HTTP_REQUEST(http); - - if (http->curl.handle) - { - CURL_SetHeader(&http->curl, CURLOPT_HTTPHEADER); - curl_easy_setopt(http->curl.handle, CURLOPT_URL, Plugin_Scr_GetString(1)); - curl_easy_setopt(http->curl.handle, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(http->curl.handle, CURLOPT_NOPROGRESS, 1L); - curl_easy_setopt(http->curl.handle, CURLOPT_WRITEFUNCTION, HTTP_WriteString); - curl_easy_setopt(http->curl.handle, CURLOPT_WRITEDATA, &http->response); - CURL_SetOpts(&http->curl); - - http->curl.worker = Plugin_AsyncWorker(asyncHandler, http, &HTTP_Execute, NULL); - } - Plugin_Scr_AddBool(qtrue); -} - -void GScr_HTTP_GetFile() -{ - CHECK_PARAMS(3, "Usage: HTTP_GetFile(, , )"); - - HTTP_REQUEST* http = (HTTP_REQUEST*)Plugin_Scr_GetInt(0); - const char* filepath = Plugin_Scr_GetString(1); - - CHECK_HTTP_REQUEST(http); - - strcpy((char*)http->file.filename, filepath); - http->file.stream = fopen(filepath, "wb"); - - if (!http->file.stream) - { - Plugin_Printf("File not found.\n"); - Plugin_Scr_AddBool(qfalse); - http->curl.worker->status = ASYNC_FAILURE; - return; - } - if (http->curl.handle) - { - CURL_SetHeader(&http->curl, CURLOPT_HTTPHEADER); - curl_easy_setopt(http->curl.handle, CURLOPT_URL, Plugin_Scr_GetString(2)); - curl_easy_setopt(http->curl.handle, CURLOPT_NOPROGRESS, 1L); - curl_easy_setopt(http->curl.handle, CURLOPT_WRITEFUNCTION, HTTP_WriteFile); - curl_easy_setopt(http->curl.handle, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(http->curl.handle, CURLOPT_WRITEDATA, http->file.stream); - CURL_SetOpts(&http->curl); - - http->curl.worker = Plugin_AsyncWorker(asyncHandler, http, &HTTP_Execute, NULL); - } - Plugin_Scr_AddBool(qtrue); -} - -void GScr_HTTP_Post() -{ - CHECK_PARAMS(3, "Usage: HTTP_PostString(, , )"); - - HTTP_REQUEST* http = (HTTP_REQUEST*)Plugin_Scr_GetInt(0); - - CHECK_HTTP_REQUEST(http); - - if (http->curl.handle) - { - CURL_SetHeader(&http->curl, CURLOPT_HTTPHEADER); - curl_easy_setopt(http->curl.handle, CURLOPT_URL, Plugin_Scr_GetString(2)); - curl_easy_setopt(http->curl.handle, CURLOPT_POSTFIELDS, Plugin_Scr_GetString(1)); - curl_easy_setopt(http->curl.handle, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(http->curl.handle, CURLOPT_NOPROGRESS, 1L); - curl_easy_setopt(http->curl.handle, CURLOPT_WRITEFUNCTION, HTTP_WriteString); - curl_easy_setopt(http->curl.handle, CURLOPT_WRITEDATA, &http->response); - CURL_SetOpts(&http->curl); - - http->curl.worker = Plugin_AsyncWorker(asyncHandler, http, &HTTP_Execute, NULL); - } - Plugin_Scr_AddBool(qtrue); -} - -void GScr_HTTP_PostFile() -{ - CHECK_PARAMS(3, "Usage: HTTP_PostFile(, , )"); - - HTTP_REQUEST* http = (HTTP_REQUEST*)Plugin_Scr_GetInt(0); - const char* filepath = Plugin_Scr_GetString(1); - - CHECK_HTTP_REQUEST(http); - - // Check file - strcpy((char*)http->file.filename, filepath); - http->file.stream = fopen(filepath, "rb"); - - if (http->file.stream) - { - fseek(http->file.stream, 0, SEEK_END); - http->response.len = ftell(http->file.stream); - fseek(http->file.stream, 0, SEEK_SET); - http->response.buffer = malloc(http->response.len * sizeof(char)); - - if (http->response.buffer) - fread(http->response.buffer, 1, http->response.len, http->file.stream); - fclose(http->file.stream); - } - else - { - Plugin_Printf("File not found.\n"); - Plugin_Scr_AddBool(qfalse); - http->curl.worker->status = ASYNC_FAILURE; - return; - } - - // Post file - if (http->curl.handle) - { - CURL_SetHeader(&http->curl, CURLOPT_HTTPHEADER); - curl_easy_setopt(http->curl.handle, CURLOPT_URL, Plugin_Scr_GetString(2)); - curl_easy_setopt(http->curl.handle, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(http->curl.handle, CURLOPT_POSTFIELDSIZE, http->response.len); - curl_easy_setopt(http->curl.handle, CURLOPT_POSTFIELDS, http->response.buffer); - curl_easy_setopt(http->curl.handle, CURLOPT_NOPROGRESS, 1L); - curl_easy_setopt(http->curl.handle, CURLOPT_WRITEFUNCTION, HTTP_WriteString); - curl_easy_setopt(http->curl.handle, CURLOPT_WRITEDATA, &http->response); - CURL_SetOpts(&http->curl); - - http->curl.worker = Plugin_AsyncWorker(asyncHandler, http, &HTTP_Execute, NULL); - } - Plugin_Scr_AddBool(qtrue); -} - -void GScr_HTTP_Response() -{ - CHECK_PARAMS(1, "Usage: HTTP_Response()"); - - HTTP_REQUEST* http = (HTTP_REQUEST*)Plugin_Scr_GetInt(0); - - CHECK_HTTP_REQUEST(http); - - Plugin_Scr_AddString(http->response.buffer ? http->response.buffer : ""); -} - -size_t HTTP_WriteFile(void* ptr, size_t size, size_t nmemb, void* stream) -{ - return fwrite(ptr, size, nmemb, (FILE*)stream); -} - -size_t HTTP_WriteString(void* ptr, size_t size, size_t nmemb, void* stream) -{ - HTTP_RESPONSE* res = (HTTP_RESPONSE*)stream; - size_t new_len = res->len + size * nmemb; - if (res->buffer == NULL) - res->buffer = (char*)malloc(new_len + 1); - else - { - char* tmp = (char*)realloc(res->buffer, new_len + 1); - if (tmp != NULL) - res->buffer = tmp; - } - - memcpy(res->buffer + res->len, ptr, size * nmemb); - res->buffer[new_len] = '\0'; - res->len = new_len; - - return size * nmemb; -} - -void HTTP_Working(qboolean state) -{ - http_handler.working = state; -} - -void HTTP_Execute(uv_work_t* req) -{ - async_worker* worker = (async_worker*)req->data; - HTTP_REQUEST* http = (HTTP_REQUEST*)worker->data; - int running = 0; - - do - { - const CURLMcode res = curl_multi_perform(http->curl.multiHandle, &running); - if (res != CURLM_OK) - { - Sys_PrintF("curl_multi_perform() failed: %s\n", curl_multi_strerror(res)); - Plugin_AsyncWorkerDone(req, ASYNC_FAILURE); - return; - } - } - while (running && worker->status != ASYNC_CANCEL); - - Plugin_AsyncWorkerDone(req, ASYNC_SUCCESSFUL); -} +#include "http.h" + +#include +#include + +HTTP_HANDLER http_handler = { 0 }; + +void GScr_HTTP_Init() +{ + CHECK_PARAMS(0, "Usage: HTTP_Init()"); + + HTTP_REQUEST* http = (HTTP_REQUEST*)calloc(1, sizeof(HTTP_REQUEST)); + http->curl.handle = curl_easy_init(); + http->curl.multiHandle = curl_multi_init(); + curl_multi_add_handle(http->curl.multiHandle, http->curl.handle); + + HTTP_Working(qtrue); + Plugin_Scr_AddInt((int)http); +} + +void GScr_HTTP_Free() +{ + CHECK_PARAMS(1, "Usage: HTTP_Free()"); + + HTTP_REQUEST* http = (HTTP_REQUEST*)Plugin_Scr_GetInt(0); + + CHECK_HTTP_REQUEST(http); + + CURL_OptCleanup(&http->curl); + CURL_HeaderCleanup(&http->curl); + + if (http->curl.multiHandle) + { + curl_multi_remove_handle(http->curl.multiHandle, http->curl.handle); + curl_multi_cleanup(http->curl.multiHandle); + } + if (http->curl.handle) + curl_easy_cleanup(http->curl.handle); + if (http->response.buffer) + free(http->response.buffer); + if (http->file.stream) + fclose(http->file.stream); + free(http); + + HTTP_Working(qfalse); + Plugin_Scr_AddBool(qtrue); +} + +void GScr_HTTP_Get() +{ + CHECK_PARAMS(2, "Usage: HTTP_GetString(, )"); + + HTTP_REQUEST* http = (HTTP_REQUEST*)Plugin_Scr_GetInt(0); + + CHECK_HTTP_REQUEST(http); + + if (http->curl.handle) + { + CURL_SetHeader(&http->curl, CURLOPT_HTTPHEADER); + curl_easy_setopt(http->curl.handle, CURLOPT_URL, Plugin_Scr_GetString(1)); + curl_easy_setopt(http->curl.handle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(http->curl.handle, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(http->curl.handle, CURLOPT_WRITEFUNCTION, HTTP_WriteString); + curl_easy_setopt(http->curl.handle, CURLOPT_WRITEDATA, &http->response); + CURL_SetOpts(&http->curl); + + http->curl.worker = Plugin_AsyncWorker(asyncHandler, http, &HTTP_Execute, NULL); + } + Plugin_Scr_AddBool(qtrue); +} + +void GScr_HTTP_GetFile() +{ + CHECK_PARAMS(3, "Usage: HTTP_GetFile(, , )"); + + HTTP_REQUEST* http = (HTTP_REQUEST*)Plugin_Scr_GetInt(0); + const char* filepath = Plugin_Scr_GetString(1); + + CHECK_HTTP_REQUEST(http); + + strcpy((char*)http->file.filename, filepath); + http->file.stream = fopen(filepath, "wb"); + + if (!http->file.stream) + { + Plugin_Printf("File not found.\n"); + Plugin_Scr_AddBool(qfalse); + http->curl.worker->status = ASYNC_FAILURE; + return; + } + if (http->curl.handle) + { + CURL_SetHeader(&http->curl, CURLOPT_HTTPHEADER); + curl_easy_setopt(http->curl.handle, CURLOPT_URL, Plugin_Scr_GetString(2)); + curl_easy_setopt(http->curl.handle, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(http->curl.handle, CURLOPT_WRITEFUNCTION, HTTP_WriteFile); + curl_easy_setopt(http->curl.handle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(http->curl.handle, CURLOPT_WRITEDATA, http->file.stream); + CURL_SetOpts(&http->curl); + + http->curl.worker = Plugin_AsyncWorker(asyncHandler, http, &HTTP_Execute, NULL); + } + Plugin_Scr_AddBool(qtrue); +} + +void GScr_HTTP_Post() +{ + CHECK_PARAMS(3, "Usage: HTTP_PostString(, , )"); + + HTTP_REQUEST* http = (HTTP_REQUEST*)Plugin_Scr_GetInt(0); + + CHECK_HTTP_REQUEST(http); + + if (http->curl.handle) + { + CURL_SetHeader(&http->curl, CURLOPT_HTTPHEADER); + curl_easy_setopt(http->curl.handle, CURLOPT_URL, Plugin_Scr_GetString(2)); + curl_easy_setopt(http->curl.handle, CURLOPT_POSTFIELDS, Plugin_Scr_GetString(1)); + curl_easy_setopt(http->curl.handle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(http->curl.handle, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(http->curl.handle, CURLOPT_WRITEFUNCTION, HTTP_WriteString); + curl_easy_setopt(http->curl.handle, CURLOPT_WRITEDATA, &http->response); + CURL_SetOpts(&http->curl); + + http->curl.worker = Plugin_AsyncWorker(asyncHandler, http, &HTTP_Execute, NULL); + } + Plugin_Scr_AddBool(qtrue); +} + +void GScr_HTTP_PostFile() +{ + CHECK_PARAMS(3, "Usage: HTTP_PostFile(, , )"); + + HTTP_REQUEST* http = (HTTP_REQUEST*)Plugin_Scr_GetInt(0); + const char* filepath = Plugin_Scr_GetString(1); + + CHECK_HTTP_REQUEST(http); + + // Check file + strcpy((char*)http->file.filename, filepath); + http->file.stream = fopen(filepath, "rb"); + + if (http->file.stream) + { + fseek(http->file.stream, 0, SEEK_END); + http->response.len = ftell(http->file.stream); + fseek(http->file.stream, 0, SEEK_SET); + http->response.buffer = malloc(http->response.len * sizeof(char)); + + if (http->response.buffer) + fread(http->response.buffer, 1, http->response.len, http->file.stream); + fclose(http->file.stream); + } + else + { + Plugin_Printf("File not found.\n"); + Plugin_Scr_AddBool(qfalse); + http->curl.worker->status = ASYNC_FAILURE; + return; + } + + // Post file + if (http->curl.handle) + { + CURL_SetHeader(&http->curl, CURLOPT_HTTPHEADER); + curl_easy_setopt(http->curl.handle, CURLOPT_URL, Plugin_Scr_GetString(2)); + curl_easy_setopt(http->curl.handle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(http->curl.handle, CURLOPT_POSTFIELDSIZE, http->response.len); + curl_easy_setopt(http->curl.handle, CURLOPT_POSTFIELDS, http->response.buffer); + curl_easy_setopt(http->curl.handle, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(http->curl.handle, CURLOPT_WRITEFUNCTION, HTTP_WriteString); + curl_easy_setopt(http->curl.handle, CURLOPT_WRITEDATA, &http->response); + CURL_SetOpts(&http->curl); + + http->curl.worker = Plugin_AsyncWorker(asyncHandler, http, &HTTP_Execute, NULL); + } + Plugin_Scr_AddBool(qtrue); +} + +void GScr_HTTP_Response() +{ + CHECK_PARAMS(1, "Usage: HTTP_Response()"); + + HTTP_REQUEST* http = (HTTP_REQUEST*)Plugin_Scr_GetInt(0); + + CHECK_HTTP_REQUEST(http); + + Plugin_Scr_AddString(http->response.buffer ? http->response.buffer : ""); +} + +size_t HTTP_WriteFile(void* ptr, size_t size, size_t nmemb, void* stream) +{ + return fwrite(ptr, size, nmemb, (FILE*)stream); +} + +size_t HTTP_WriteString(void* ptr, size_t size, size_t nmemb, void* stream) +{ + HTTP_RESPONSE* res = (HTTP_RESPONSE*)stream; + size_t new_len = res->len + size * nmemb; + if (res->buffer == NULL) + res->buffer = (char*)malloc(new_len + 1); + else + { + char* tmp = (char*)realloc(res->buffer, new_len + 1); + if (tmp != NULL) + res->buffer = tmp; + } + + memcpy(res->buffer + res->len, ptr, size * nmemb); + res->buffer[new_len] = '\0'; + res->len = new_len; + + return size * nmemb; +} + +void HTTP_Working(qboolean state) +{ + http_handler.working = state; +} + +void HTTP_Execute(uv_work_t* req) +{ + async_worker* worker = (async_worker*)req->data; + HTTP_REQUEST* http = (HTTP_REQUEST*)worker->data; + int running = 0; + + do + { + const CURLMcode res = curl_multi_perform(http->curl.multiHandle, &running); + if (res != CURLM_OK) + { + Sys_PrintF("curl_multi_perform() failed: %s\n", curl_multi_strerror(res)); + Plugin_AsyncWorkerDone(req, ASYNC_FAILURE); + return; + } + } while (running && worker->status != ASYNC_CANCEL); + + Plugin_AsyncWorkerDone(req, ASYNC_SUCCESSFUL); +} diff --git a/src/net/http.h b/src/net/http.h index 5ebeb21..5dbd563 100644 --- a/src/net/http.h +++ b/src/net/http.h @@ -1,91 +1,91 @@ -#pragma once -#include "curl.h" - -#define CHECK_HTTP_REQUEST(http) \ -CURL_CHECK_ERROR(!http, "HTTP request not found."); \ -CURL_CHECK_ERROR(http->curl.worker && http->curl.worker->status == ASYNC_PENDING, "HTTP request is pending."); - -typedef struct -{ - char* buffer; - size_t len; -} HTTP_RESPONSE; - -typedef struct -{ - const char filename[MAX_PATH]; - FILE* stream; -} HTTP_FILE; - -typedef struct -{ - qboolean working; -} HTTP_HANDLER; - -typedef struct -{ - CURL_REQUEST curl; - HTTP_RESPONSE response; - HTTP_FILE file; -} HTTP_REQUEST; - -extern HTTP_HANDLER http_handler; - -/// -/// Init the HTTP request. -/// -void GScr_HTTP_Init(); - -/// -/// Free an HTTP request. -/// -void GScr_HTTP_Free(); - -/// -/// Upload a file to an HTTP url. -/// -void GScr_HTTP_PostFile(); - -/// -/// Post a string to an HTTP url. -/// -void GScr_HTTP_Post(); - -/// -/// Save a file from an HTTP url. -/// -void GScr_HTTP_GetFile(); - -/// -/// Get a string from an HTTP url. -/// -void GScr_HTTP_Get(); - -/// -/// Get the HTTP response. -/// -void GScr_HTTP_Response(); - -/// -/// File write function to use with CURL http write callback. -/// -/// -size_t HTTP_WriteFile(void* ptr, size_t size, size_t nmemb, void* stream); - -/// -/// String write function to use with CURL http write callback. -/// -/// -size_t HTTP_WriteString(void* ptr, size_t size, size_t nmemb, void* stream); - -/// -/// Set the HTTP working state. -/// -/// The working state. -void HTTP_Working(qboolean state); - -/// -/// Execute the async request. -/// -/// The worker request. -void HTTP_Execute(uv_work_t* req); +#pragma once +#include "curl.h" + +#define CHECK_HTTP_REQUEST(http) \ + CURL_CHECK_ERROR(!http, "HTTP request not found."); \ + CURL_CHECK_ERROR(http->curl.worker && http->curl.worker->status == ASYNC_PENDING, "HTTP request is pending."); + +typedef struct +{ + char* buffer; + size_t len; +} HTTP_RESPONSE; + +typedef struct +{ + const char filename[MAX_PATH]; + FILE* stream; +} HTTP_FILE; + +typedef struct +{ + qboolean working; +} HTTP_HANDLER; + +typedef struct +{ + CURL_REQUEST curl; + HTTP_RESPONSE response; + HTTP_FILE file; +} HTTP_REQUEST; + +extern HTTP_HANDLER http_handler; + +/// +/// Init the HTTP request. +/// +void GScr_HTTP_Init(); + +/// +/// Free an HTTP request. +/// +void GScr_HTTP_Free(); + +/// +/// Upload a file to an HTTP url. +/// +void GScr_HTTP_PostFile(); + +/// +/// Post a string to an HTTP url. +/// +void GScr_HTTP_Post(); + +/// +/// Save a file from an HTTP url. +/// +void GScr_HTTP_GetFile(); + +/// +/// Get a string from an HTTP url. +/// +void GScr_HTTP_Get(); + +/// +/// Get the HTTP response. +/// +void GScr_HTTP_Response(); + +/// +/// File write function to use with CURL http write callback. +/// +/// +size_t HTTP_WriteFile(void* ptr, size_t size, size_t nmemb, void* stream); + +/// +/// String write function to use with CURL http write callback. +/// +/// +size_t HTTP_WriteString(void* ptr, size_t size, size_t nmemb, void* stream); + +/// +/// Set the HTTP working state. +/// +/// The working state. +void HTTP_Working(qboolean state); + +/// +/// Execute the async request. +/// +/// The worker request. +void HTTP_Execute(uv_work_t* req); diff --git a/src/net/mysql.c b/src/net/mysql.c index 0f72bca..ba8b044 100644 --- a/src/net/mysql.c +++ b/src/net/mysql.c @@ -8,7 +8,7 @@ MYSQL_HANDLER mysql_handler = { 0 }; void GScr_MySQL_Version() { CHECK_PARAMS(0, "Usage: SQL_Version()"); - Plugin_Scr_AddString(mysql_get_client_info()); + Plugin_Scr_AddString(mysql_get_client_info()); } void GScr_MySQL_Prepare() @@ -25,7 +25,7 @@ void GScr_MySQL_Prepare() MySQL_Free_Result(mysql); MySQL_Free_Statement(mysql); - const char *query = Plugin_Scr_GetString(0); + const char* query = Plugin_Scr_GetString(0); mysql->stmt = mysql_stmt_init(mysql->handle); if (mysql_stmt_prepare(mysql->stmt, query, strlen(query))) @@ -47,12 +47,11 @@ void GScr_MySQL_BindParam() CHECK_MYSQL_INSTANCE(mysql->handle); CHECK_MYSQL_STMT(mysql->stmt); - VariableValue *variable = Plugin_Scr_SelectParam(1); + VariableValue* variable = Plugin_Scr_SelectParam(1); enum enum_field_types type = (enum enum_field_types)Plugin_Scr_GetInt(2); - mysql->binds = !mysql->binds - ? (MYSQL_BIND*)malloc(sizeof(MYSQL_BIND)) - : (MYSQL_BIND*)realloc(mysql->binds, sizeof(MYSQL_BIND) * (mysql->bindsLength + 1)); + mysql->binds = !mysql->binds ? (MYSQL_BIND*)malloc(sizeof(MYSQL_BIND)) + : (MYSQL_BIND*)realloc(mysql->binds, sizeof(MYSQL_BIND) * (mysql->bindsLength + 1)); void* value = NULL; int valueSize = 0; @@ -60,14 +59,14 @@ void GScr_MySQL_BindParam() switch (variable->type) { case VAR_STRING: - value = (void *)Plugin_SL_ConvertToString(variable->u.stringValue); - valueSize = strlen((const char *)value); + value = (void*)Plugin_SL_ConvertToString(variable->u.stringValue); + valueSize = strlen((const char*)value); break; case VAR_INTEGER: - value = (void *)&variable->u.intValue; + value = (void*)&variable->u.intValue; break; case VAR_FLOAT: - value = (void *)&variable->u.floatValue; + value = (void*)&variable->u.floatValue; break; } MySQL_PrepareBindBuffer(&mysql->binds[mysql->bindsLength], value, valueSize, type); @@ -119,7 +118,7 @@ void GScr_MySQL_ListDB() CHECK_PARAMS(0, "Usage: SQL_ListDB()"); CHECK_MYSQL_INSTANCE(mysql_handler.handle); - MYSQL_RES *result = mysql_list_dbs(mysql_handler.handle, "%"); + MYSQL_RES* result = mysql_list_dbs(mysql_handler.handle, "%"); MYSQL_ROW row; if (!result) @@ -142,7 +141,7 @@ void GScr_MySQL_ListTables() CHECK_PARAMS(0, "Usage: SQL_ListTables()"); CHECK_MYSQL_INSTANCE(mysql_handler.handle); - MYSQL_RES *result = mysql_list_tables(mysql_handler.handle, "%"); + MYSQL_RES* result = mysql_list_tables(mysql_handler.handle, "%"); MYSQL_ROW row; if (!result) @@ -165,10 +164,10 @@ void GScr_MySQL_EscapeString() CHECK_PARAMS(1, "Usage: SQL_EscapeString()"); CHECK_MYSQL_INSTANCE(mysql_handler.handle); - const char *from = Plugin_Scr_GetString(0); - char to[strlen(from) + 1]; - unsigned long len = mysql_real_escape_string(mysql_handler.handle, to, from, strlen(from)); - to[len] = '\0'; + const char* from = Plugin_Scr_GetString(0); + char to[strlen(from) + 1]; + unsigned long len = mysql_real_escape_string(mysql_handler.handle, to, from, strlen(from)); + to[len] = '\0'; Plugin_Scr_AddString(to); } @@ -177,12 +176,12 @@ void GScr_MySQL_HexString() { CHECK_PARAMS(1, "Usage: SQL_HexString()"); - const char *from = Plugin_Scr_GetString(0); - char to[(strlen(from) * 2) + 1]; - unsigned long len = mysql_hex_string(to, from, strlen(from)); - to[len] = '\0'; + const char* from = Plugin_Scr_GetString(0); + char to[(strlen(from) * 2) + 1]; + unsigned long len = mysql_hex_string(to, from, strlen(from)); + to[len] = '\0'; - Plugin_Scr_AddString(to); + Plugin_Scr_AddString(to); } void GScr_MySQL_SelectDB() @@ -208,7 +207,7 @@ void GScr_MySQL_FetchFields() CHECK_MYSQL_REQUEST(mysql); CHECK_MYSQL_INSTANCE(mysql->handle); - MYSQL_RES *res = mysql->result ? mysql->result : mysql->resultStmt; + MYSQL_RES* res = mysql->result ? mysql->result : mysql->resultStmt; if (!res) { Plugin_Scr_AddUndefined(); @@ -221,7 +220,7 @@ void GScr_MySQL_FetchFields() mysql_field_seek(res, 0); for (int i = 0; i < num_fields; i++) { - MYSQL_FIELD *field = mysql_fetch_field(res); + MYSQL_FIELD* field = mysql_fetch_field(res); if (!field) { Plugin_Scr_AddUndefined(); @@ -385,15 +384,15 @@ void GScr_MySQL_Connect() qboolean reconnect = qtrue; mysql_options(mysql_handler.handle, MYSQL_OPT_RECONNECT, &reconnect); - if (!mysql_real_connect(mysql_handler.handle, /* MYSQL structure to use */ - Plugin_Scr_GetString(0), /* server hostname or IP address */ - Plugin_Scr_GetString(2), /* handle user */ - Plugin_Scr_GetString(3), /* password */ - NULL, /* default database to use, NULL for none */ - Plugin_Scr_GetInt(1), /* port number, 0 for default */ - NULL, /* socket file or named pipe name */ - 0 /* connection flags */ - )) + if (!mysql_real_connect(mysql_handler.handle, /* MYSQL structure to use */ + Plugin_Scr_GetString(0), /* server hostname or IP address */ + Plugin_Scr_GetString(2), /* handle user */ + Plugin_Scr_GetString(3), /* password */ + NULL, /* default database to use, NULL for none */ + Plugin_Scr_GetInt(1), /* port number, 0 for default */ + NULL, /* socket file or named pipe name */ + 0 /* connection flags */ + )) { // Close previous connection Plugin_Scr_Error("SQL_Connect(): Connection failed"); @@ -683,7 +682,7 @@ void MySQL_Execute(uv_work_t* req) Plugin_AsyncWorkerDone(req, ASYNC_SUCCESSFUL); } -void MySQL_Free_Statement(MYSQL_REQUEST *mysql) +void MySQL_Free_Statement(MYSQL_REQUEST* mysql) { if (mysql->stmt) { diff --git a/src/net/mysql.h b/src/net/mysql.h index e291042..e2a34ea 100644 --- a/src/net/mysql.h +++ b/src/net/mysql.h @@ -1,28 +1,25 @@ #pragma once #include "sys/system.h" -#include #include +#include -#define MYSQL_CHECK_ERROR(x, msg) \ -if (x) \ -{ \ - Plugin_Scr_Error(msg); \ - return; \ -} +#define MYSQL_CHECK_ERROR(x, msg) \ + if (x) \ + { \ + Plugin_Scr_Error(msg); \ + return; \ + } -#define CHECK_MYSQL_REQUEST(mysql) \ -MYSQL_CHECK_ERROR(!mysql, "MySQL request not found."); \ -MYSQL_CHECK_ERROR(mysql->worker && mysql->worker->status == ASYNC_PENDING, "MySQL request is pending."); +#define CHECK_MYSQL_REQUEST(mysql) \ + MYSQL_CHECK_ERROR(!mysql, "MySQL request not found."); \ + MYSQL_CHECK_ERROR(mysql->worker && mysql->worker->status == ASYNC_PENDING, "MySQL request is pending."); -#define CHECK_MYSQL_WORKING() \ -MYSQL_CHECK_ERROR(mysql_handler.working, "MySQL is processing another request."); +#define CHECK_MYSQL_WORKING() MYSQL_CHECK_ERROR(mysql_handler.working, "MySQL is processing another request."); -#define CHECK_MYSQL_INSTANCE(handle) \ -MYSQL_CHECK_ERROR(!handle, "MySQL connection not found."); +#define CHECK_MYSQL_INSTANCE(handle) MYSQL_CHECK_ERROR(!handle, "MySQL connection not found."); -#define CHECK_MYSQL_STMT(stmt) \ -MYSQL_CHECK_ERROR(!stmt, "MySQL statement not found."); +#define CHECK_MYSQL_STMT(stmt) MYSQL_CHECK_ERROR(!stmt, "MySQL statement not found."); typedef struct { @@ -33,13 +30,13 @@ typedef struct typedef struct { - async_worker *worker; - MYSQL *handle; - MYSQL_RES *result; - MYSQL_RES *resultStmt; - MYSQL_STMT *stmt; - MYSQL_BIND *binds; - MYSQL_BIND *bindsResult; + async_worker* worker; + MYSQL* handle; + MYSQL_RES* result; + MYSQL_RES* resultStmt; + MYSQL_STMT* stmt; + MYSQL_BIND* binds; + MYSQL_BIND* bindsResult; char query[1024]; int bindsLength; int bindsResultLength; diff --git a/src/plugin.c b/src/plugin.c index 90c2326..b35536a 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -1,22 +1,22 @@ #include "data/regex.h" #include "data/zip.h" +#include "linq/delegates.h" #include "linq/enumerables.h" #include "linq/predicates.h" -#include "linq/delegates.h" #include "net/curl.h" -#include "net/http.h" #include "net/ftp.h" +#include "net/http.h" #include "net/mysql.h" #include "sys/system.h" -#include "utils/utils.h" -#include "utils/stringutils.h" #include "utils/convert.h" #include "utils/math.h" #include "utils/player.h" +#include "utils/stringutils.h" +#include "utils/utils.h" #define FUNCTION(name, function) Plugin_ScrReplaceFunction(name, function) #define METHOD(name, function) Plugin_ScrReplaceMethod(name, function) @@ -47,185 +47,185 @@ PCL int OnInit() mysql_handler.code = mysql_library_init(0, NULL, NULL); // gsclib - FUNCTION("gsclib_init", &GScr_GSCLIB_Init); + FUNCTION("gsclib_init", &GScr_GSCLIB_Init); // data/file - FUNCTION("file_create", &GScr_FILE_Create); - FUNCTION("file_open", &GScr_FILE_Open); - FUNCTION("file_close", &GScr_FILE_Close); - FUNCTION("file_exists", &GScr_FILE_Exists); - FUNCTION("file_readline", &GScr_FILE_ReadLine); - FUNCTION("file_writeline", &GScr_FILE_WriteLine); - FUNCTION("file_readlines", &GScr_FILE_ReadLines); - FUNCTION("file_writelines", &GScr_FILE_WriteLines); - FUNCTION("file_read", &GScr_FILE_Read); - FUNCTION("file_write", &GScr_FILE_Write); - FUNCTION("file_seek", &GScr_FILE_Seek); - FUNCTION("file_delete", &GScr_FILE_Delete); - FUNCTION("file_mkdir", &GScr_FILE_MkDir); - FUNCTION("file_rmdir", &GScr_FILE_RmDir); - FUNCTION("file_readdir", &GScr_FILE_ReadDir); + FUNCTION("file_create", &GScr_FILE_Create); + FUNCTION("file_open", &GScr_FILE_Open); + FUNCTION("file_close", &GScr_FILE_Close); + FUNCTION("file_exists", &GScr_FILE_Exists); + FUNCTION("file_readline", &GScr_FILE_ReadLine); + FUNCTION("file_writeline", &GScr_FILE_WriteLine); + FUNCTION("file_readlines", &GScr_FILE_ReadLines); + FUNCTION("file_writelines", &GScr_FILE_WriteLines); + FUNCTION("file_read", &GScr_FILE_Read); + FUNCTION("file_write", &GScr_FILE_Write); + FUNCTION("file_seek", &GScr_FILE_Seek); + FUNCTION("file_delete", &GScr_FILE_Delete); + FUNCTION("file_mkdir", &GScr_FILE_MkDir); + FUNCTION("file_rmdir", &GScr_FILE_RmDir); + FUNCTION("file_readdir", &GScr_FILE_ReadDir); // data/regex - FUNCTION("regexmatch", &GScr_RegexMatch); - FUNCTION("regexsplit", &GScr_RegexSplit); - FUNCTION("regexreplace", &GScr_RegexReplace); + FUNCTION("regexmatch", &GScr_RegexMatch); + FUNCTION("regexsplit", &GScr_RegexSplit); + FUNCTION("regexreplace", &GScr_RegexReplace); // data/zip - FUNCTION("zip_add", &GScr_ZIP_Add); - FUNCTION("zip_rename", &GScr_ZIP_Rename); - FUNCTION("zip_delete", &GScr_ZIP_Delete); - FUNCTION("zip_open", &GScr_ZIP_Open); - FUNCTION("zip_close", &GScr_ZIP_Close); + FUNCTION("zip_add", &GScr_ZIP_Add); + FUNCTION("zip_rename", &GScr_ZIP_Rename); + FUNCTION("zip_delete", &GScr_ZIP_Delete); + FUNCTION("zip_open", &GScr_ZIP_Open); + FUNCTION("zip_close", &GScr_ZIP_Close); // linq/delegates - FUNCTION("select", &GScr_LINQ_Select); - FUNCTION("foreach", &GScr_LINQ_Foreach); - FUNCTION("aggregate", &GScr_LINQ_Aggregate); + FUNCTION("select", &GScr_LINQ_Select); + FUNCTION("foreach", &GScr_LINQ_Foreach); + FUNCTION("aggregate", &GScr_LINQ_Aggregate); // linq/predicates - FUNCTION("all", &GScr_LINQ_All); - FUNCTION("where", &GScr_LINQ_Where); - FUNCTION("any", &GScr_LINQ_Any); - FUNCTION("last", &GScr_LINQ_Last); - FUNCTION("first", &GScr_LINQ_First); - FUNCTION("count", &GScr_LINQ_Count); + FUNCTION("all", &GScr_LINQ_All); + FUNCTION("where", &GScr_LINQ_Where); + FUNCTION("any", &GScr_LINQ_Any); + FUNCTION("last", &GScr_LINQ_Last); + FUNCTION("first", &GScr_LINQ_First); + FUNCTION("count", &GScr_LINQ_Count); // linq/enumerables - FUNCTION("getmin", &GScr_LINQ_Min); - FUNCTION("getmax", &GScr_LINQ_Max); - FUNCTION("cast", &GScr_LINQ_Cast); - FUNCTION("oftype", &GScr_LINQ_OfType); - FUNCTION("sort", &GScr_LINQ_Sort); - FUNCTION("average", &GScr_LINQ_Average); - FUNCTION("sum", &GScr_LINQ_Sum); - FUNCTION("range", &GScr_LINQ_Range); - FUNCTION("repeat", &GScr_LINQ_Repeat); - FUNCTION("reverse", &GScr_LINQ_Reverse); - FUNCTION("concat", &GScr_LINQ_Concat); - FUNCTION("chunk", &GScr_LINQ_Chunk); - FUNCTION("contains", &GScr_LINQ_Contains); - FUNCTION("indexof", &GScr_LINQ_IndexOf); - FUNCTION("remove", &GScr_LINQ_Remove); - FUNCTION("removeat", &GScr_LINQ_RemoveAt); + FUNCTION("getmin", &GScr_LINQ_Min); + FUNCTION("getmax", &GScr_LINQ_Max); + FUNCTION("cast", &GScr_LINQ_Cast); + FUNCTION("oftype", &GScr_LINQ_OfType); + FUNCTION("sort", &GScr_LINQ_Sort); + FUNCTION("average", &GScr_LINQ_Average); + FUNCTION("sum", &GScr_LINQ_Sum); + FUNCTION("range", &GScr_LINQ_Range); + FUNCTION("repeat", &GScr_LINQ_Repeat); + FUNCTION("reverse", &GScr_LINQ_Reverse); + FUNCTION("concat", &GScr_LINQ_Concat); + FUNCTION("chunk", &GScr_LINQ_Chunk); + FUNCTION("contains", &GScr_LINQ_Contains); + FUNCTION("indexof", &GScr_LINQ_IndexOf); + FUNCTION("remove", &GScr_LINQ_Remove); + FUNCTION("removeat", &GScr_LINQ_RemoveAt); // net/curl - FUNCTION("curl_version", &GScr_CURL_Version); - FUNCTION("curl_init", &GScr_CURL_Init); - FUNCTION("curl_addheader", &GScr_CURL_AddHeader); - FUNCTION("curl_headercleanup", &GScr_CURL_HeaderCleanup); - FUNCTION("curl_optcleanup", &GScr_CURL_OptCleanup); - FUNCTION("curl_addopt", &GScr_CURL_AddOpt); - FUNCTION("curl_free", &GScr_CURL_Free); + FUNCTION("curl_version", &GScr_CURL_Version); + FUNCTION("curl_init", &GScr_CURL_Init); + FUNCTION("curl_addheader", &GScr_CURL_AddHeader); + FUNCTION("curl_headercleanup", &GScr_CURL_HeaderCleanup); + FUNCTION("curl_optcleanup", &GScr_CURL_OptCleanup); + FUNCTION("curl_addopt", &GScr_CURL_AddOpt); + FUNCTION("curl_free", &GScr_CURL_Free); // net/http - FUNCTION("http_init", &GScr_HTTP_Init); - FUNCTION("http_post", &GScr_HTTP_Post); - FUNCTION("http_postfile", &GScr_HTTP_PostFile); - FUNCTION("http_get", &GScr_HTTP_Get); - FUNCTION("http_getfile", &GScr_HTTP_GetFile); - FUNCTION("http_response", &GScr_HTTP_Response); - FUNCTION("http_free", &GScr_HTTP_Free); + FUNCTION("http_init", &GScr_HTTP_Init); + FUNCTION("http_post", &GScr_HTTP_Post); + FUNCTION("http_postfile", &GScr_HTTP_PostFile); + FUNCTION("http_get", &GScr_HTTP_Get); + FUNCTION("http_getfile", &GScr_HTTP_GetFile); + FUNCTION("http_response", &GScr_HTTP_Response); + FUNCTION("http_free", &GScr_HTTP_Free); // net/ftp - FUNCTION("sftp_connect", &GScr_SFTP_Connect); - FUNCTION("ftp_connect", &GScr_FTP_Connect); - FUNCTION("ftp_init", &GScr_FTP_Init); - FUNCTION("ftp_close", &GScr_FTP_Close); - FUNCTION("ftp_shell", &GScr_FTP_Shell); - FUNCTION("ftp_postfile", &GScr_FTP_PostFile); - FUNCTION("ftp_getfile", &GScr_FTP_GetFile); - FUNCTION("ftp_free", &GScr_FTP_Free); + FUNCTION("sftp_connect", &GScr_SFTP_Connect); + FUNCTION("ftp_connect", &GScr_FTP_Connect); + FUNCTION("ftp_init", &GScr_FTP_Init); + FUNCTION("ftp_close", &GScr_FTP_Close); + FUNCTION("ftp_shell", &GScr_FTP_Shell); + FUNCTION("ftp_postfile", &GScr_FTP_PostFile); + FUNCTION("ftp_getfile", &GScr_FTP_GetFile); + FUNCTION("ftp_free", &GScr_FTP_Free); // net/mysql - FUNCTION("sql_prepare", &GScr_MySQL_Prepare); - FUNCTION("sql_bindparam", &GScr_MySQL_BindParam); - FUNCTION("sql_bindresult", &GScr_MySQL_BindResult); - FUNCTION("sql_execute", &GScr_MySQL_Execute); - FUNCTION("sql_escapestring", &GScr_MySQL_EscapeString); - FUNCTION("sql_hexstring", &GScr_MySQL_HexString); - FUNCTION("sql_selectdb", &GScr_MySQL_SelectDB); - FUNCTION("sql_query", &GScr_MySQL_Query); - FUNCTION("sql_numrows", &GScr_MySQL_NumRows); - FUNCTION("sql_numfields", &GScr_MySQL_NumFields); - FUNCTION("sql_affectedrows", &GScr_MySQL_AffectedRows); - FUNCTION("sql_fetchrowsdict", &GScr_MySQL_FetchRowsDict); - FUNCTION("sql_fetchrows", &GScr_MySQL_FetchRows); - FUNCTION("sql_fetchrowdict", &GScr_MySQL_FetchRowDict); - FUNCTION("sql_fetchrow", &GScr_MySQL_FetchRow); - FUNCTION("sql_fetchfields", &GScr_MySQL_FetchFields); - FUNCTION("sql_listdb", &GScr_MySQL_ListDB); - FUNCTION("sql_listtables", &GScr_MySQL_ListTables); - FUNCTION("sql_version", &GScr_MySQL_Version); - FUNCTION("sql_connect", &GScr_MySQL_Connect); - FUNCTION("sql_close", &GScr_MySQL_Close); - FUNCTION("sql_free", &GScr_MySQL_Free); + FUNCTION("sql_prepare", &GScr_MySQL_Prepare); + FUNCTION("sql_bindparam", &GScr_MySQL_BindParam); + FUNCTION("sql_bindresult", &GScr_MySQL_BindResult); + FUNCTION("sql_execute", &GScr_MySQL_Execute); + FUNCTION("sql_escapestring", &GScr_MySQL_EscapeString); + FUNCTION("sql_hexstring", &GScr_MySQL_HexString); + FUNCTION("sql_selectdb", &GScr_MySQL_SelectDB); + FUNCTION("sql_query", &GScr_MySQL_Query); + FUNCTION("sql_numrows", &GScr_MySQL_NumRows); + FUNCTION("sql_numfields", &GScr_MySQL_NumFields); + FUNCTION("sql_affectedrows", &GScr_MySQL_AffectedRows); + FUNCTION("sql_fetchrowsdict", &GScr_MySQL_FetchRowsDict); + FUNCTION("sql_fetchrows", &GScr_MySQL_FetchRows); + FUNCTION("sql_fetchrowdict", &GScr_MySQL_FetchRowDict); + FUNCTION("sql_fetchrow", &GScr_MySQL_FetchRow); + FUNCTION("sql_fetchfields", &GScr_MySQL_FetchFields); + FUNCTION("sql_listdb", &GScr_MySQL_ListDB); + FUNCTION("sql_listtables", &GScr_MySQL_ListTables); + FUNCTION("sql_version", &GScr_MySQL_Version); + FUNCTION("sql_connect", &GScr_MySQL_Connect); + FUNCTION("sql_close", &GScr_MySQL_Close); + FUNCTION("sql_free", &GScr_MySQL_Free); // sys/system - FUNCTION("system", &GScr_System); - FUNCTION("sysprint", &GScr_SysPrint); - FUNCTION("sysprintln", &GScr_SysPrintLn); - FUNCTION("comprint", &GScr_ComPrint); - FUNCTION("comprintln", &GScr_ComPrintLn); - FUNCTION("getsystime", &GScr_GetSysTime); - FUNCTION("criticalsection", &GScr_CriticalSection); - FUNCTION("criticalsections", &GScr_CriticalSections); - FUNCTION("entercriticalsection", &GScr_EnterCriticalSection); - FUNCTION("leavecriticalsection", &GScr_LeaveCriticalSection); - FUNCTION("asyncstatus", &GScr_AsyncStatus); - FUNCTION("iswindows", &GScr_IsWindows); - FUNCTION("islinux", &GScr_IsLinux); - FUNCTION("cod4x_version", &GScr_CoD4X_Version); - FUNCTION("cgsc_version", &GScr_CGSC_Version); - FUNCTION("gsclib_version", &GScr_GSCLIB_Version); - FUNCTION("exit", &GScr_Exit); + FUNCTION("system", &GScr_System); + FUNCTION("sysprint", &GScr_SysPrint); + FUNCTION("sysprintln", &GScr_SysPrintLn); + FUNCTION("comprint", &GScr_ComPrint); + FUNCTION("comprintln", &GScr_ComPrintLn); + FUNCTION("getsystime", &GScr_GetSysTime); + FUNCTION("criticalsection", &GScr_CriticalSection); + FUNCTION("criticalsections", &GScr_CriticalSections); + FUNCTION("entercriticalsection", &GScr_EnterCriticalSection); + FUNCTION("leavecriticalsection", &GScr_LeaveCriticalSection); + FUNCTION("asyncstatus", &GScr_AsyncStatus); + FUNCTION("iswindows", &GScr_IsWindows); + FUNCTION("islinux", &GScr_IsLinux); + FUNCTION("cod4x_version", &GScr_CoD4X_Version); + FUNCTION("cgsc_version", &GScr_CGSC_Version); + FUNCTION("gsclib_version", &GScr_GSCLIB_Version); + FUNCTION("exit", &GScr_Exit); // utils/utils - FUNCTION("gettype", &GScr_GetType); - FUNCTION("ternary", &GScr_Ternary); - FUNCTION("ifundef", &GScr_IfUndef); + FUNCTION("gettype", &GScr_GetType); + FUNCTION("ternary", &GScr_Ternary); + FUNCTION("ifundef", &GScr_IfUndef); // utils/convert - FUNCTION("tostring", &GScr_ToString); - FUNCTION("toint", &GScr_ToInt); - FUNCTION("tofloat", &GScr_ToFloat); + FUNCTION("tostring", &GScr_ToString); + FUNCTION("toint", &GScr_ToInt); + FUNCTION("tofloat", &GScr_ToFloat); // utils/stringutils - FUNCTION("isnullorempty", &GScr_IsNullOrEmpty); - FUNCTION("isstringalpha", &GScr_IsStringAlpha); - FUNCTION("isstringfloat", &GScr_IsStringFloat); - FUNCTION("isstringint", &GScr_IsStringInt); - FUNCTION("torgb", &GScr_ToRGB); - FUNCTION("hextorgb", &GScr_HexToRGB); - FUNCTION("fmt", &GScr_Fmt); - FUNCTION("trim", &GScr_Trim); - FUNCTION("startswith", &GScr_StartsWith); - FUNCTION("endswith", &GScr_EndsWith); - FUNCTION("strjoin", &GScr_StrJoin); - FUNCTION("replace", &GScr_Replace); - FUNCTION("pathjoin", &GScr_PathJoin); + FUNCTION("isnullorempty", &GScr_IsNullOrEmpty); + FUNCTION("isstringalpha", &GScr_IsStringAlpha); + FUNCTION("isstringfloat", &GScr_IsStringFloat); + FUNCTION("isstringint", &GScr_IsStringInt); + FUNCTION("torgb", &GScr_ToRGB); + FUNCTION("hextorgb", &GScr_HexToRGB); + FUNCTION("fmt", &GScr_Fmt); + FUNCTION("trim", &GScr_Trim); + FUNCTION("startswith", &GScr_StartsWith); + FUNCTION("endswith", &GScr_EndsWith); + FUNCTION("strjoin", &GScr_StrJoin); + FUNCTION("replace", &GScr_Replace); + FUNCTION("pathjoin", &GScr_PathJoin); // utils/math - FUNCTION("fmod", &GScr_fmod); - FUNCTION("tan1", &GScr_tan1); - FUNCTION("atan1", &GScr_atan1); - FUNCTION("atan2", &GScr_atan2); - FUNCTION("cos1", &GScr_cos1); - FUNCTION("acos1", &GScr_acos1); - FUNCTION("sin1", &GScr_sin1); - FUNCTION("asin1", &GScr_asin1); + FUNCTION("fmod", &GScr_fmod); + FUNCTION("tan1", &GScr_tan1); + FUNCTION("atan1", &GScr_atan1); + FUNCTION("atan2", &GScr_atan2); + FUNCTION("cos1", &GScr_cos1); + FUNCTION("acos1", &GScr_acos1); + FUNCTION("sin1", &GScr_sin1); + FUNCTION("asin1", &GScr_asin1); // utils/player - METHOD("getip", &GScr_GetIP); - METHOD("getforwardmove", &GScr_GetForwardMove); - METHOD("getrightmove", &GScr_GetRightMove); - METHOD("getjumporigin", &GScr_GetJumpOrigin); - METHOD("pmflags", &GScr_PmFlags); - METHOD("setpmflags", &GScr_SetPmFlags); - METHOD("pmtime", &GScr_PmTime); - METHOD("setpmtime", &GScr_SetPmTime); - METHOD("pmtype", &GScr_PmType); - METHOD("weaponflags", &GScr_WeaponFlags); + METHOD("getip", &GScr_GetIP); + METHOD("getforwardmove", &GScr_GetForwardMove); + METHOD("getrightmove", &GScr_GetRightMove); + METHOD("getjumporigin", &GScr_GetJumpOrigin); + METHOD("pmflags", &GScr_PmFlags); + METHOD("setpmflags", &GScr_SetPmFlags); + METHOD("pmtime", &GScr_PmTime); + METHOD("setpmtime", &GScr_SetPmTime); + METHOD("pmtype", &GScr_PmType); + METHOD("weaponflags", &GScr_WeaponFlags); return 0; } @@ -258,6 +258,14 @@ PCL void OnInfoRequest(pluginInfo_t *info) info->pluginVersion.major = GSCLIB_VERSION_MAJOR; info->pluginVersion.minor = GSCLIB_VERSION_MINOR; strncpy(info->fullName, "gsclib", sizeof(info->fullName)); - strncpy(info->shortDescription, "gsclib acts as a standard library extension for the Call of Duty 4 scripting language.", sizeof(info->shortDescription)); - strncpy(info->longDescription, "gsclib acts as a standard library extension for the Call of Duty 4 scripting language. The features this library provides consists of an FTP/FTPS/SFTP client, an HTTP/HTTPS client, Regular Expresison (RegEx) support, Language Integrated Query (Linq) support, a MySQL connector for databases, casting/type conversion and other type utilities, and much more. More detailed information on each feature can be found in the documentation section.", sizeof(info->longDescription)); + strncpy(info->shortDescription, + "gsclib acts as a standard library extension for the Call of Duty 4 scripting language.", + sizeof(info->shortDescription)); + strncpy(info->longDescription, + "gsclib acts as a standard library extension for the Call of Duty 4 scripting language. The features this " + "library provides consists of an FTP/FTPS/SFTP client, an HTTP/HTTPS client, Regular Expresison (RegEx) " + "support, Language Integrated Query (Linq) support, a MySQL connector for databases, casting/type conversion " + "and other type utilities, and much more. More detailed information on each feature can be found in the " + "documentation section.", + sizeof(info->longDescription)); } diff --git a/src/sys/system.c b/src/sys/system.c index c735147..8cb0a40 100644 --- a/src/sys/system.c +++ b/src/sys/system.c @@ -1,285 +1,286 @@ -#include "system.h" -#include "utils/utils.h" -#include "utils/vsnprintf.h" - -#include -#include -#include - -critical_sections sections = { 0 }; -async_handler* asyncHandler = NULL; - -void GScr_System() -{ - CHECK_PARAMS(1, "Usage: System()"); - Plugin_Scr_AddInt(system(Plugin_Scr_GetString(0))); -} - -void GScr_GetSysTime() -{ - CHECK_PARAMS(0, "Usage: GetSysTime()"); - Plugin_Scr_AddInt(Plugin_Milliseconds()); -} - -void GScr_Exit() -{ - CHECK_PARAMS(1, "Usage: Exit()"); - exit(Plugin_Scr_GetInt(0)); -} - -void GScr_ComPrint() -{ - Scr_PrintF(qfalse, &Plugin_Printf); -} - -void GScr_ComPrintLn() -{ - Scr_PrintF(qtrue, &Plugin_Printf); -} - -void GScr_SysPrint() -{ - Scr_PrintF(qfalse, &Sys_PrintF); -} - -void GScr_SysPrintLn() -{ - Scr_PrintF(qtrue, &Sys_PrintF); -} - -void GScr_CriticalSection() -{ - CHECK_PARAMS(1, "Usage: CriticalSection()"); - - const char* name = Plugin_Scr_GetString(0); - for (int i = 0; i < sections.length; i++) - { - if (!strcmp(name, sections.list[i].id)) - return; - } - sections.list = !sections.list - ? (critical_section*)malloc(sizeof(critical_section)) - : (critical_section*)realloc(sections.list, (sections.length + 1) * sizeof(critical_section)); - - critical_section* section = §ions.list[sections.length++]; - strcpy(section->id, name); - section->locked = qfalse; -} - -void GScr_CriticalSections() -{ - CHECK_PARAMS(0, "Usage: CriticalSections()"); - - if (!sections.length) - return; - - Plugin_Scr_MakeArray(); - for (int i = 0; i < sections.length; i++) - { - critical_section* section = §ions.list[i]; - Plugin_Scr_AddInt(section->locked); - Plugin_Scr_AddArrayStringIndexed(Plugin_Scr_AllocString(section->id)); - } -} - -void GScr_EnterCriticalSection() -{ - CHECK_PARAMS(1, "Usage: EnterCriticalSection()"); - - critical_section* section = NULL; - const char* name = Plugin_Scr_GetString(0); - - for (int i = 0; i < sections.length; i++) - { - if (!strcmp(name, sections.list[i].id)) - { - section = §ions.list[i]; - break; - } - } - if (!section) - { - Plugin_Scr_Error(fmt("EnterCriticalSection(): section %s not found.", name)); - return; - } - if (!section->locked) - { - section->locked = qtrue; - Plugin_Scr_AddBool(qtrue); - return; - } - Plugin_Scr_AddBool(qfalse); -} - -void GScr_LeaveCriticalSection() -{ - CHECK_PARAMS(1, "Usage: LeaveCriticalSection()"); - - critical_section* section = NULL; - const char* name = Plugin_Scr_GetString(0); - - for (int i = 0; i < sections.length; i++) - { - if (!strcmp(name, sections.list[i].id)) - { - section = §ions.list[i]; - break; - } - } - if (!section) - { - Plugin_Scr_Error(fmt("LeaveCriticalSection(): section %s not found.", name)); - return; - } - section->locked = qfalse; -} - -void GScr_AsyncStatus() -{ - CHECK_PARAMS(1, "Usage: AsyncStatus()"); - - async_worker** worker = (async_worker**)Plugin_Scr_GetInt(0); - if (!worker || !(*worker)) - { - Plugin_Scr_AddInt(0); - return; - } - Plugin_Scr_AddInt((*worker)->status); -} - -void GScr_IsWindows() -{ -#ifdef _WIN32 - Plugin_Scr_AddBool(qtrue); -#else - Plugin_Scr_AddBool(qfalse); -#endif -} - -void GScr_IsLinux() -{ -#ifdef _WIN32 - Plugin_Scr_AddBool(qfalse); -#else - Plugin_Scr_AddBool(qtrue); -#endif -} - -void GScr_CoD4X_Version() -{ - Plugin_Scr_AddFloat(Plugin_Sys_GetCommonVersion()); -} - -void GScr_GSCLIB_Version() -{ - char version[20] = { 0 }; - sprintf(version, "%d.%d", GSCLIB_VERSION_MAJOR, GSCLIB_VERSION_MINOR); - Plugin_Scr_AddFloat(atof(version)); -} - -void GScr_CGSC_Version() -{ - Plugin_Scr_AddFloat(Plugin_CGSC_Version()); -} - -void Sys_PrintF(const char* format, ...) -{ - va_list argptr; - va_start(argptr, format); - fprintf(stderr, format, argptr); - va_end(argptr); -} - -void Scr_PrintF(qboolean newLine, void (*print)(const char*, ...)) -{ - const int argCount = Plugin_Scr_GetNumParam(); - if (argCount == 0) - { - print(newLine ? "\n" : ""); - return; - } - char buffer[MAX_STRING_CHARS] = { 0 }; - char* format = Plugin_Scr_GetString(0); - - if (argCount == 1) - { - Sys_AnsiColorPrint(fmt("%s%s", format, newLine ? "\n" : ""), print); - return; - } - VariableValueArray args = Plugin_Scr_CreateArray(argCount - 1); - - for (int i = 1; i < argCount; i++) - args.items[i - 1] = *Plugin_Scr_SelectParam(i); - - Scr_vsnprintf(buffer, sizeof(buffer), format, args); - if (newLine) strcat(buffer, "\n"); - Sys_AnsiColorPrint(buffer, print); - - Plugin_Scr_FreeArray(&args); -} - -void Sys_AnsiColorPrint(const char* msg, void (*print)(const char*, ...)) -{ - int length = 0; - static char buffer[MAXPRINTMSG] = { 0 }; - - while (*msg) - { - if (Q_IsColorString(msg) || *msg == '\n') - { - if (length > 0) - { - buffer[length] = '\0'; - print(buffer); - length = 0; - } - if (*msg == '\n') - { - print("\033[0m\n"); - msg++; - } - else - { - snprintf(buffer, sizeof(buffer), "\033[1;%dm", q3ToAnsi[ColorIndex(*(msg + 1))]); - print(buffer); - msg += 2; - } - } - else - { - if (length >= MAXPRINTMSG - 1) - break; - buffer[length] = *msg; - length++; - msg++; - } - } - if (length > 0) - { - buffer[length] = '\0'; - print(buffer); - } -} - -void ShutdownCriticalSections() -{ - if (sections.list) - { - free(sections.list); - sections.list = NULL; - sections.length = 0; - } -} - -void AsyncHandlerRestart() -{ - AsyncHandlerShutdown(); - asyncHandler = Plugin_AsyncInit(); -} - -void AsyncHandlerShutdown() -{ - Plugin_Printf("[GSCLIB] Shutting down all async tasks...\n"); - - Plugin_AsyncShutdown(asyncHandler); -} +#include "system.h" +#include "utils/utils.h" +#include "utils/vsnprintf.h" + +#include +#include +#include + +critical_sections sections = { 0 }; +async_handler* asyncHandler = NULL; + +void GScr_System() +{ + CHECK_PARAMS(1, "Usage: System()"); + Plugin_Scr_AddInt(system(Plugin_Scr_GetString(0))); +} + +void GScr_GetSysTime() +{ + CHECK_PARAMS(0, "Usage: GetSysTime()"); + Plugin_Scr_AddInt(Plugin_Milliseconds()); +} + +void GScr_Exit() +{ + CHECK_PARAMS(1, "Usage: Exit()"); + exit(Plugin_Scr_GetInt(0)); +} + +void GScr_ComPrint() +{ + Scr_PrintF(qfalse, &Plugin_Printf); +} + +void GScr_ComPrintLn() +{ + Scr_PrintF(qtrue, &Plugin_Printf); +} + +void GScr_SysPrint() +{ + Scr_PrintF(qfalse, &Sys_PrintF); +} + +void GScr_SysPrintLn() +{ + Scr_PrintF(qtrue, &Sys_PrintF); +} + +void GScr_CriticalSection() +{ + CHECK_PARAMS(1, "Usage: CriticalSection()"); + + const char* name = Plugin_Scr_GetString(0); + for (int i = 0; i < sections.length; i++) + { + if (!strcmp(name, sections.list[i].id)) + return; + } + sections.list = !sections.list + ? (critical_section*)malloc(sizeof(critical_section)) + : (critical_section*)realloc(sections.list, (sections.length + 1) * sizeof(critical_section)); + + critical_section* section = §ions.list[sections.length++]; + strcpy(section->id, name); + section->locked = qfalse; +} + +void GScr_CriticalSections() +{ + CHECK_PARAMS(0, "Usage: CriticalSections()"); + + if (!sections.length) + return; + + Plugin_Scr_MakeArray(); + for (int i = 0; i < sections.length; i++) + { + critical_section* section = §ions.list[i]; + Plugin_Scr_AddInt(section->locked); + Plugin_Scr_AddArrayStringIndexed(Plugin_Scr_AllocString(section->id)); + } +} + +void GScr_EnterCriticalSection() +{ + CHECK_PARAMS(1, "Usage: EnterCriticalSection()"); + + critical_section* section = NULL; + const char* name = Plugin_Scr_GetString(0); + + for (int i = 0; i < sections.length; i++) + { + if (!strcmp(name, sections.list[i].id)) + { + section = §ions.list[i]; + break; + } + } + if (!section) + { + Plugin_Scr_Error(fmt("EnterCriticalSection(): section %s not found.", name)); + return; + } + if (!section->locked) + { + section->locked = qtrue; + Plugin_Scr_AddBool(qtrue); + return; + } + Plugin_Scr_AddBool(qfalse); +} + +void GScr_LeaveCriticalSection() +{ + CHECK_PARAMS(1, "Usage: LeaveCriticalSection()"); + + critical_section* section = NULL; + const char* name = Plugin_Scr_GetString(0); + + for (int i = 0; i < sections.length; i++) + { + if (!strcmp(name, sections.list[i].id)) + { + section = §ions.list[i]; + break; + } + } + if (!section) + { + Plugin_Scr_Error(fmt("LeaveCriticalSection(): section %s not found.", name)); + return; + } + section->locked = qfalse; +} + +void GScr_AsyncStatus() +{ + CHECK_PARAMS(1, "Usage: AsyncStatus()"); + + async_worker** worker = (async_worker**)Plugin_Scr_GetInt(0); + if (!worker || !(*worker)) + { + Plugin_Scr_AddInt(0); + return; + } + Plugin_Scr_AddInt((*worker)->status); +} + +void GScr_IsWindows() +{ +#ifdef _WIN32 + Plugin_Scr_AddBool(qtrue); +#else + Plugin_Scr_AddBool(qfalse); +#endif +} + +void GScr_IsLinux() +{ +#ifdef _WIN32 + Plugin_Scr_AddBool(qfalse); +#else + Plugin_Scr_AddBool(qtrue); +#endif +} + +void GScr_CoD4X_Version() +{ + Plugin_Scr_AddFloat(Plugin_Sys_GetCommonVersion()); +} + +void GScr_GSCLIB_Version() +{ + char version[20] = { 0 }; + sprintf(version, "%d.%d", GSCLIB_VERSION_MAJOR, GSCLIB_VERSION_MINOR); + Plugin_Scr_AddFloat(atof(version)); +} + +void GScr_CGSC_Version() +{ + Plugin_Scr_AddFloat(Plugin_CGSC_Version()); +} + +void Sys_PrintF(const char* format, ...) +{ + va_list argptr; + va_start(argptr, format); + fprintf(stderr, format, argptr); + va_end(argptr); +} + +void Scr_PrintF(qboolean newLine, void (*print)(const char*, ...)) +{ + const int argCount = Plugin_Scr_GetNumParam(); + if (argCount == 0) + { + print(newLine ? "\n" : ""); + return; + } + char buffer[MAX_STRING_CHARS] = { 0 }; + char* format = Plugin_Scr_GetString(0); + + if (argCount == 1) + { + Sys_AnsiColorPrint(fmt("%s%s", format, newLine ? "\n" : ""), print); + return; + } + VariableValueArray args = Plugin_Scr_CreateArray(argCount - 1); + + for (int i = 1; i < argCount; i++) + args.items[i - 1] = *Plugin_Scr_SelectParam(i); + + Scr_vsnprintf(buffer, sizeof(buffer), format, args); + if (newLine) + strcat(buffer, "\n"); + Sys_AnsiColorPrint(buffer, print); + + Plugin_Scr_FreeArray(&args); +} + +void Sys_AnsiColorPrint(const char* msg, void (*print)(const char*, ...)) +{ + int length = 0; + static char buffer[MAXPRINTMSG] = { 0 }; + + while (*msg) + { + if (Q_IsColorString(msg) || *msg == '\n') + { + if (length > 0) + { + buffer[length] = '\0'; + print(buffer); + length = 0; + } + if (*msg == '\n') + { + print("\033[0m\n"); + msg++; + } + else + { + snprintf(buffer, sizeof(buffer), "\033[1;%dm", q3ToAnsi[ColorIndex(*(msg + 1))]); + print(buffer); + msg += 2; + } + } + else + { + if (length >= MAXPRINTMSG - 1) + break; + buffer[length] = *msg; + length++; + msg++; + } + } + if (length > 0) + { + buffer[length] = '\0'; + print(buffer); + } +} + +void ShutdownCriticalSections() +{ + if (sections.list) + { + free(sections.list); + sections.list = NULL; + sections.length = 0; + } +} + +void AsyncHandlerRestart() +{ + AsyncHandlerShutdown(); + asyncHandler = Plugin_AsyncInit(); +} + +void AsyncHandlerShutdown() +{ + Plugin_Printf("[GSCLIB] Shutting down all async tasks...\n"); + + Plugin_AsyncShutdown(asyncHandler); +} diff --git a/src/utils/__test__/vsnprintf.test.c b/src/utils/__test__/vsnprintf.test.c index b7b9699..fcaef5b 100644 --- a/src/utils/__test__/vsnprintf.test.c +++ b/src/utils/__test__/vsnprintf.test.c @@ -1,28 +1,28 @@ -#include "utils/vsnprintf.h" - -#include -#include - -TEST test_vsnprintf() -{ - char buffer[MAX_STRING_CHARS]; - const char* format = "%d %d"; - const int argCount = 2; - - VariableValueArray args = Plugin_Scr_CreateArray(argCount); - args.items[0].type = VAR_INTEGER; - args.items[0].u.intValue = 1; - args.items[1].type = VAR_INTEGER; - args.items[1].u.intValue = 2; - - Scr_vsnprintf(buffer, sizeof(buffer), format, args); - Plugin_Scr_FreeArray(&args); - - ASSERT_STR_EQ(buffer, "1 2"); - PASS(); -} - -SUITE(Suite_utils_vsnprintf) -{ - RUN_TEST(test_vsnprintf); -} +#include "utils/vsnprintf.h" + +#include +#include + +TEST test_vsnprintf() +{ + char buffer[MAX_STRING_CHARS]; + const char* format = "%d %d"; + const int argCount = 2; + + VariableValueArray args = Plugin_Scr_CreateArray(argCount); + args.items[0].type = VAR_INTEGER; + args.items[0].u.intValue = 1; + args.items[1].type = VAR_INTEGER; + args.items[1].u.intValue = 2; + + Scr_vsnprintf(buffer, sizeof(buffer), format, args); + Plugin_Scr_FreeArray(&args); + + ASSERT_STR_EQ(buffer, "1 2"); + PASS(); +} + +SUITE(Suite_utils_vsnprintf) +{ + RUN_TEST(test_vsnprintf); +} diff --git a/src/utils/convert.c b/src/utils/convert.c index 1b0aa2e..6a107a3 100644 --- a/src/utils/convert.c +++ b/src/utils/convert.c @@ -1,91 +1,88 @@ -#include "convert.h" - -#include -#include -#include - -void GScr_ToInt() -{ - CHECK_PARAMS(1, "Usage: ToInt()"); - - VariableValue *var = Plugin_Scr_SelectParam(0); - switch (var->type) - { - case VAR_ISTRING: - case VAR_STRING: - { - const char *nptr = Plugin_SL_ConvertToString(var->u.stringValue); - char *endptr = NULL; - long number = strtol(nptr, &endptr, 10); - - if (*endptr == '\0') - Plugin_Scr_AddInt((int)number); - break; - } - case VAR_VECTOR: - Plugin_Scr_AddInt((int)(var->u.vectorValue[0] + var->u.vectorValue[1] + var->u.vectorValue[2])); - break; - case VAR_INTEGER: - Plugin_Scr_AddInt(var->u.intValue); - break; - case VAR_FLOAT: - Plugin_Scr_AddInt((int)var->u.floatValue); - break; - } -} - -void GScr_ToFloat() -{ - CHECK_PARAMS(1, "Usage: ToFloat()"); - - VariableValue *var = Plugin_Scr_SelectParam(0); - switch (var->type) - { - case VAR_ISTRING: - case VAR_STRING: - { - const char *nptr = Plugin_SL_ConvertToString(var->u.stringValue); - char *endptr = NULL; - float number = strtof(nptr, &endptr); - - if (*endptr == '\0') - Plugin_Scr_AddFloat(number); - break; - } - case VAR_VECTOR: - Plugin_Scr_AddFloat(var->u.vectorValue[0] + var->u.vectorValue[1] + var->u.vectorValue[2]); - break; - case VAR_INTEGER: - Plugin_Scr_AddFloat((float)var->u.intValue); - break; - case VAR_FLOAT: - Plugin_Scr_AddFloat(var->u.floatValue); - break; - } -} - -void GScr_ToString() -{ - CHECK_PARAMS(1, "Usage: ToString()"); - - VariableValue *var = Plugin_Scr_SelectParam(0); - switch (var->type) - { - case VAR_ISTRING: - case VAR_STRING: - Plugin_Scr_AddString(Plugin_SL_ConvertToString(var->u.stringValue)); - break; - case VAR_VECTOR: - Plugin_Scr_AddString(fmt("(%f, %f, %f)", - var->u.vectorValue[0], - var->u.vectorValue[1], - var->u.vectorValue[2])); - break; - case VAR_INTEGER: - Plugin_Scr_AddString(fmt("%d", var->u.intValue)); - break; - case VAR_FLOAT: - Plugin_Scr_AddString(fmt("%f", var->u.floatValue)); - break; - } -} +#include "convert.h" + +#include +#include +#include + +void GScr_ToInt() +{ + CHECK_PARAMS(1, "Usage: ToInt()"); + + VariableValue *var = Plugin_Scr_SelectParam(0); + switch (var->type) + { + case VAR_ISTRING: + case VAR_STRING: + { + const char *nptr = Plugin_SL_ConvertToString(var->u.stringValue); + char *endptr = NULL; + long number = strtol(nptr, &endptr, 10); + + if (*endptr == '\0') + Plugin_Scr_AddInt((int)number); + break; + } + case VAR_VECTOR: + Plugin_Scr_AddInt((int)(var->u.vectorValue[0] + var->u.vectorValue[1] + var->u.vectorValue[2])); + break; + case VAR_INTEGER: + Plugin_Scr_AddInt(var->u.intValue); + break; + case VAR_FLOAT: + Plugin_Scr_AddInt((int)var->u.floatValue); + break; + } +} + +void GScr_ToFloat() +{ + CHECK_PARAMS(1, "Usage: ToFloat()"); + + VariableValue *var = Plugin_Scr_SelectParam(0); + switch (var->type) + { + case VAR_ISTRING: + case VAR_STRING: + { + const char *nptr = Plugin_SL_ConvertToString(var->u.stringValue); + char *endptr = NULL; + float number = strtof(nptr, &endptr); + + if (*endptr == '\0') + Plugin_Scr_AddFloat(number); + break; + } + case VAR_VECTOR: + Plugin_Scr_AddFloat(var->u.vectorValue[0] + var->u.vectorValue[1] + var->u.vectorValue[2]); + break; + case VAR_INTEGER: + Plugin_Scr_AddFloat((float)var->u.intValue); + break; + case VAR_FLOAT: + Plugin_Scr_AddFloat(var->u.floatValue); + break; + } +} + +void GScr_ToString() +{ + CHECK_PARAMS(1, "Usage: ToString()"); + + VariableValue *var = Plugin_Scr_SelectParam(0); + switch (var->type) + { + case VAR_ISTRING: + case VAR_STRING: + Plugin_Scr_AddString(Plugin_SL_ConvertToString(var->u.stringValue)); + break; + case VAR_VECTOR: + Plugin_Scr_AddString(fmt("(%f, %f, %f)", var->u.vectorValue[0], var->u.vectorValue[1], var->u.vectorValue[2])); + break; + case VAR_INTEGER: + Plugin_Scr_AddString(fmt("%d", var->u.intValue)); + break; + case VAR_FLOAT: + Plugin_Scr_AddString(fmt("%f", var->u.floatValue)); + break; + } +} diff --git a/src/utils/player.c b/src/utils/player.c index 44a8235..0288ce2 100644 --- a/src/utils/player.c +++ b/src/utils/player.c @@ -1,137 +1,129 @@ -#include "player.h" - -void GScr_GetIP(scr_entref_t num) -{ - client_t* cl = Plugin_GetClientForClientNum(num); - - if (!cl) - { - Plugin_Scr_ObjectError("not a client\n"); - return; - } - - char ip[128]; - Plugin_NET_AdrToStringShortMT(&cl->netchan.remoteAddress, ip, sizeof(ip)); - Plugin_Scr_AddString(ip); -} - -void GScr_GetForwardMove(scr_entref_t num) -{ - client_t* cl = Plugin_GetClientForClientNum(num); - - if (!cl) - { - Plugin_Scr_ObjectError("not a client\n"); - return; - } - - Plugin_Scr_AddInt((int)cl->lastUsercmd.forwardmove); -} - -void GScr_GetRightMove(scr_entref_t num) -{ - client_t* cl = Plugin_GetClientForClientNum(num); - - if (!cl) - { - Plugin_Scr_ObjectError("not a client\n"); - return; - } - - Plugin_Scr_AddInt((int)cl->lastUsercmd.rightmove); -} - -void GScr_GetJumpOrigin(scr_entref_t num) -{ - gentity_t* ent = Plugin_GetGentityForEntityNum(num); - - if (!ent || !ent->client) - { - Plugin_Scr_ObjectError("not a client\n"); - return; - } - - Plugin_Scr_AddInt(ent->client->ps.jumpOriginZ); -} - -void GScr_PmFlags(scr_entref_t num) -{ - gentity_t *ent = Plugin_GetGentityForEntityNum(num); - - if (!ent || !ent->client) - { - Plugin_Scr_ObjectError("not a client\n"); - return; - } - - Plugin_Scr_AddInt(ent->client->ps.pm_flags); -} - -void GScr_SetPmFlags(scr_entref_t num) -{ - CHECK_PARAMS(1, "Usage: SetPmFlags()"); - - gentity_t* ent = Plugin_GetGentityForEntityNum(num); - int flags = Plugin_Scr_GetInt(0); - - if (!ent || !ent->client) - { - Plugin_Scr_ObjectError("not a client\n"); - return; - } - ent->client->ps.pm_flags = flags; -} - -void GScr_PmTime(scr_entref_t num) -{ - gentity_t *ent = Plugin_GetGentityForEntityNum(num); - - if (!ent || !ent->client) - { - Plugin_Scr_ObjectError("not a client\n"); - return; - } - - Plugin_Scr_AddInt(ent->client->ps.pm_time); -} - -void GScr_SetPmTime(scr_entref_t num) -{ - CHECK_PARAMS(1, "Usage: SetPmTime(