Fixed the code style in *.c files to two spaces indentation and add a linter named funstx to Fun. (0.39.0)
This commit is contained in:
parent
33001a7ad2
commit
03b2532474
237 changed files with 17550 additions and 13911 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(fun VERSION 0.38.16 LANGUAGES C)
|
project(fun VERSION 0.39.0 LANGUAGES C)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 99)
|
set(CMAKE_C_STANDARD 99)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
|
@ -46,7 +46,16 @@ message(STATUS "===========================")
|
||||||
|
|
||||||
# Convenience aggregate target (like 'build' in Makefile)
|
# Convenience aggregate target (like 'build' in Makefile)
|
||||||
add_custom_target(build
|
add_custom_target(build
|
||||||
DEPENDS fun fun_test test_opcodes
|
DEPENDS fun funstx fun_test test_opcodes
|
||||||
|
)
|
||||||
|
|
||||||
|
# Formatting helper target: run clang-format over C/C++ sources using .clang-format
|
||||||
|
add_custom_target(format
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E echo "Running clang-format on sources..."
|
||||||
|
COMMAND /bin/sh -c "command -v clang-format >/dev/null 2>&1 || { echo 'clang-format not found in PATH' >&2; exit 1; }"
|
||||||
|
COMMAND /bin/sh -c "set -e; for pat in '*.c' '*.h' '*.cpp' '*.hpp'; do find ${CMAKE_SOURCE_DIR}/src -type f -name \"\$pat\" -print0; done | xargs -0 -n 50 clang-format -i"
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
COMMENT "Apply .clang-format (IndentWidth=2) to all source files"
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Rust (Cargo) integration: optionally build and link a staticlib with opcode examples ---
|
# --- Rust (Cargo) integration: optionally build and link a staticlib with opcode examples ---
|
||||||
|
|
@ -400,6 +409,11 @@ install(TARGETS fun
|
||||||
RUNTIME DESTINATION /usr/bin
|
RUNTIME DESTINATION /usr/bin
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Also install the syntax-checker CLI by default
|
||||||
|
install(TARGETS funstx
|
||||||
|
RUNTIME DESTINATION /usr/bin
|
||||||
|
)
|
||||||
|
|
||||||
# Libs
|
# Libs
|
||||||
install(DIRECTORY lib/
|
install(DIRECTORY lib/
|
||||||
DESTINATION /usr/share/fun/lib
|
DESTINATION /usr/share/fun/lib
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,12 @@ if(FUN_WITH_REPL)
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(fun PRIVATE fun_core)
|
target_link_libraries(fun PRIVATE fun_core)
|
||||||
|
|
||||||
|
# Executable: funstx (syntax checker CLI)
|
||||||
|
add_executable(funstx
|
||||||
|
${CMAKE_SOURCE_DIR}/src/funstx.c
|
||||||
|
)
|
||||||
|
target_link_libraries(funstx PRIVATE fun_core)
|
||||||
|
|
||||||
# Internal test programs
|
# Internal test programs
|
||||||
add_executable(fun_test
|
add_executable(fun_test
|
||||||
${CMAKE_SOURCE_DIR}/src/fun_test.c)
|
${CMAKE_SOURCE_DIR}/src/fun_test.c)
|
||||||
|
|
|
||||||
497
src/bytecode.c
497
src/bytecode.c
|
|
@ -8,8 +8,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "bytecode.h"
|
#include "bytecode.h"
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
Bytecode *bytecode_new(void) {
|
Bytecode *bytecode_new(void) {
|
||||||
Bytecode *bc = (Bytecode *)malloc(sizeof(Bytecode));
|
Bytecode *bc = (Bytecode *)malloc(sizeof(Bytecode));
|
||||||
|
|
@ -55,171 +55,336 @@ void bytecode_free(Bytecode *bc) {
|
||||||
|
|
||||||
static const char *opcode_name(OpCode op) {
|
static const char *opcode_name(OpCode op) {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case OP_NOP: return "NOP";
|
case OP_NOP:
|
||||||
case OP_LOAD_CONST: return "LOAD_CONST";
|
return "NOP";
|
||||||
case OP_LOAD_LOCAL: return "LOAD_LOCAL";
|
case OP_LOAD_CONST:
|
||||||
case OP_STORE_LOCAL: return "STORE_LOCAL";
|
return "LOAD_CONST";
|
||||||
case OP_LOAD_GLOBAL: return "LOAD_GLOBAL";
|
case OP_LOAD_LOCAL:
|
||||||
case OP_STORE_GLOBAL: return "STORE_GLOBAL";
|
return "LOAD_LOCAL";
|
||||||
case OP_ADD: return "ADD";
|
case OP_STORE_LOCAL:
|
||||||
case OP_SUB: return "SUB";
|
return "STORE_LOCAL";
|
||||||
case OP_MUL: return "MUL";
|
case OP_LOAD_GLOBAL:
|
||||||
case OP_DIV: return "DIV";
|
return "LOAD_GLOBAL";
|
||||||
case OP_LT: return "LT";
|
case OP_STORE_GLOBAL:
|
||||||
case OP_LTE: return "LTE";
|
return "STORE_GLOBAL";
|
||||||
case OP_GT: return "GT";
|
case OP_ADD:
|
||||||
case OP_GTE: return "GTE";
|
return "ADD";
|
||||||
case OP_EQ: return "EQ";
|
case OP_SUB:
|
||||||
case OP_NEQ: return "NEQ";
|
return "SUB";
|
||||||
case OP_POP: return "POP";
|
case OP_MUL:
|
||||||
case OP_JUMP: return "JUMP";
|
return "MUL";
|
||||||
case OP_JUMP_IF_FALSE: return "JUMP_IF_FALSE";
|
case OP_DIV:
|
||||||
case OP_CALL: return "CALL";
|
return "DIV";
|
||||||
case OP_RETURN: return "RETURN";
|
case OP_LT:
|
||||||
case OP_PRINT: return "PRINT";
|
return "LT";
|
||||||
case OP_ECHO: return "ECHO";
|
case OP_LTE:
|
||||||
case OP_HALT: return "HALT";
|
return "LTE";
|
||||||
case OP_MOD: return "MOD";
|
case OP_GT:
|
||||||
case OP_AND: return "AND";
|
return "GT";
|
||||||
case OP_OR: return "OR";
|
case OP_GTE:
|
||||||
case OP_NOT: return "NOT";
|
return "GTE";
|
||||||
case OP_DUP: return "DUP";
|
case OP_EQ:
|
||||||
case OP_SWAP: return "SWAP";
|
return "EQ";
|
||||||
case OP_MAKE_ARRAY: return "MAKE_ARRAY";
|
case OP_NEQ:
|
||||||
case OP_INDEX_GET: return "INDEX_GET";
|
return "NEQ";
|
||||||
case OP_INDEX_SET: return "INDEX_SET";
|
case OP_POP:
|
||||||
case OP_LEN: return "LEN";
|
return "POP";
|
||||||
case OP_PUSH: return "ARR_PUSH";
|
case OP_JUMP:
|
||||||
case OP_APOP: return "ARR_POP";
|
return "JUMP";
|
||||||
case OP_SET: return "ARR_SET";
|
case OP_JUMP_IF_FALSE:
|
||||||
case OP_INSERT: return "ARR_INSERT";
|
return "JUMP_IF_FALSE";
|
||||||
case OP_REMOVE: return "ARR_REMOVE";
|
case OP_CALL:
|
||||||
case OP_SLICE: return "SLICE";
|
return "CALL";
|
||||||
case OP_TO_NUMBER: return "TO_NUMBER";
|
case OP_RETURN:
|
||||||
case OP_TO_STRING: return "TO_STRING";
|
return "RETURN";
|
||||||
case OP_TYPEOF: return "TYPEOF";
|
case OP_PRINT:
|
||||||
case OP_CAST: return "CAST";
|
return "PRINT";
|
||||||
case OP_SPLIT: return "SPLIT";
|
case OP_ECHO:
|
||||||
case OP_JOIN: return "JOIN";
|
return "ECHO";
|
||||||
case OP_SUBSTR: return "SUBSTR";
|
case OP_HALT:
|
||||||
case OP_FIND: return "FIND";
|
return "HALT";
|
||||||
case OP_REGEX_MATCH: return "REGEX_MATCH";
|
case OP_MOD:
|
||||||
case OP_REGEX_SEARCH: return "REGEX_SEARCH";
|
return "MOD";
|
||||||
case OP_REGEX_REPLACE: return "REGEX_REPLACE";
|
case OP_AND:
|
||||||
case OP_CONTAINS: return "CONTAINS";
|
return "AND";
|
||||||
case OP_INDEX_OF: return "INDEX_OF";
|
case OP_OR:
|
||||||
case OP_CLEAR: return "CLEAR";
|
return "OR";
|
||||||
case OP_ENUMERATE: return "ENUMERATE";
|
case OP_NOT:
|
||||||
case OP_ZIP: return "ZIP";
|
return "NOT";
|
||||||
case OP_MIN: return "MIN";
|
case OP_DUP:
|
||||||
case OP_MAX: return "MAX";
|
return "DUP";
|
||||||
case OP_CLAMP: return "CLAMP";
|
case OP_SWAP:
|
||||||
case OP_ABS: return "ABS";
|
return "SWAP";
|
||||||
case OP_POW: return "POW";
|
case OP_MAKE_ARRAY:
|
||||||
case OP_RANDOM_SEED: return "RANDOM_SEED";
|
return "MAKE_ARRAY";
|
||||||
case OP_RANDOM_INT: return "RANDOM_INT";
|
case OP_INDEX_GET:
|
||||||
case OP_MAKE_MAP: return "MAKE_MAP";
|
return "INDEX_GET";
|
||||||
case OP_KEYS: return "KEYS";
|
case OP_INDEX_SET:
|
||||||
case OP_VALUES: return "VALUES";
|
return "INDEX_SET";
|
||||||
case OP_HAS_KEY: return "HAS_KEY";
|
case OP_LEN:
|
||||||
case OP_READ_FILE: return "READ_FILE";
|
return "LEN";
|
||||||
case OP_WRITE_FILE: return "WRITE_FILE";
|
case OP_PUSH:
|
||||||
case OP_ENV: return "ENV";
|
return "ARR_PUSH";
|
||||||
case OP_INPUT_LINE: return "INPUT_LINE";
|
case OP_APOP:
|
||||||
case OP_PROC_RUN: return "PROC_RUN";
|
return "ARR_POP";
|
||||||
case OP_PROC_SYSTEM: return "PROC_SYSTEM";
|
case OP_SET:
|
||||||
case OP_TIME_NOW_MS: return "TIME_NOW_MS";
|
return "ARR_SET";
|
||||||
case OP_CLOCK_MONO_MS: return "CLOCK_MONO_MS";
|
case OP_INSERT:
|
||||||
case OP_DATE_FORMAT: return "DATE_FORMAT";
|
return "ARR_INSERT";
|
||||||
case OP_ENV_ALL: return "ENV_ALL";
|
case OP_REMOVE:
|
||||||
case OP_FUN_VERSION: return "FUN_VERSION";
|
return "ARR_REMOVE";
|
||||||
case OP_THREAD_SPAWN: return "THREAD_SPAWN";
|
case OP_SLICE:
|
||||||
case OP_THREAD_JOIN: return "THREAD_JOIN";
|
return "SLICE";
|
||||||
case OP_SLEEP_MS: return "SLEEP_MS";
|
case OP_TO_NUMBER:
|
||||||
case OP_RANDOM_NUMBER: return "RANDOM_NUMBER";
|
return "TO_NUMBER";
|
||||||
case OP_BAND: return "BAND";
|
case OP_TO_STRING:
|
||||||
case OP_BOR: return "BOR";
|
return "TO_STRING";
|
||||||
case OP_BXOR: return "BXOR";
|
case OP_TYPEOF:
|
||||||
case OP_BNOT: return "BNOT";
|
return "TYPEOF";
|
||||||
case OP_SHL: return "SHL";
|
case OP_CAST:
|
||||||
case OP_SHR: return "SHR";
|
return "CAST";
|
||||||
case OP_ROTL: return "ROTL";
|
case OP_SPLIT:
|
||||||
case OP_ROTR: return "ROTR";
|
return "SPLIT";
|
||||||
case OP_JSON_PARSE: return "JSON_PARSE";
|
case OP_JOIN:
|
||||||
case OP_JSON_STRINGIFY: return "JSON_STRINGIFY";
|
return "JOIN";
|
||||||
case OP_JSON_FROM_FILE: return "JSON_FROM_FILE";
|
case OP_SUBSTR:
|
||||||
case OP_JSON_TO_FILE: return "JSON_TO_FILE";
|
return "SUBSTR";
|
||||||
case OP_CURL_GET: return "CURL_GET";
|
case OP_FIND:
|
||||||
case OP_CURL_POST: return "CURL_POST";
|
return "FIND";
|
||||||
case OP_CURL_DOWNLOAD: return "CURL_DOWNLOAD";
|
case OP_REGEX_MATCH:
|
||||||
case OP_SQLITE_OPEN: return "SQLITE_OPEN";
|
return "REGEX_MATCH";
|
||||||
case OP_SQLITE_CLOSE: return "SQLITE_CLOSE";
|
case OP_REGEX_SEARCH:
|
||||||
case OP_SQLITE_EXEC: return "SQLITE_EXEC";
|
return "REGEX_SEARCH";
|
||||||
case OP_SQLITE_QUERY: return "SQLITE_QUERY";
|
case OP_REGEX_REPLACE:
|
||||||
case OP_LIBSQL_OPEN: return "LIBSQL_OPEN";
|
return "REGEX_REPLACE";
|
||||||
case OP_LIBSQL_CLOSE: return "LIBSQL_CLOSE";
|
case OP_CONTAINS:
|
||||||
case OP_LIBSQL_EXEC: return "LIBSQL_EXEC";
|
return "CONTAINS";
|
||||||
case OP_LIBSQL_QUERY: return "LIBSQL_QUERY";
|
case OP_INDEX_OF:
|
||||||
case OP_PCSC_ESTABLISH: return "PCSC_ESTABLISH";
|
return "INDEX_OF";
|
||||||
case OP_PCSC_RELEASE: return "PCSC_RELEASE";
|
case OP_CLEAR:
|
||||||
case OP_PCSC_LIST_READERS: return "PCSC_LIST_READERS";
|
return "CLEAR";
|
||||||
case OP_PCSC_CONNECT: return "PCSC_CONNECT";
|
case OP_ENUMERATE:
|
||||||
case OP_PCSC_DISCONNECT: return "PCSC_DISCONNECT";
|
return "ENUMERATE";
|
||||||
case OP_PCSC_TRANSMIT: return "PCSC_TRANSMIT";
|
case OP_ZIP:
|
||||||
case OP_PCRE2_TEST: return "PCRE2_TEST";
|
return "ZIP";
|
||||||
case OP_PCRE2_MATCH: return "PCRE2_MATCH";
|
case OP_MIN:
|
||||||
case OP_PCRE2_FINDALL: return "PCRE2_FINDALL";
|
return "MIN";
|
||||||
case OP_OPENSSL_MD5: return "OPENSSL_MD5";
|
case OP_MAX:
|
||||||
case OP_OPENSSL_SHA256: return "OPENSSL_SHA256";
|
return "MAX";
|
||||||
case OP_OPENSSL_SHA512: return "OPENSSL_SHA512";
|
case OP_CLAMP:
|
||||||
case OP_OPENSSL_RIPEMD160: return "OPENSSL_RIPEMD160";
|
return "CLAMP";
|
||||||
case OP_LIBRESSL_MD5: return "LIBRESSL_MD5";
|
case OP_ABS:
|
||||||
case OP_LIBRESSL_SHA256: return "LIBRESSL_SHA256";
|
return "ABS";
|
||||||
case OP_LIBRESSL_SHA512: return "LIBRESSL_SHA512";
|
case OP_POW:
|
||||||
case OP_LIBRESSL_RIPEMD160: return "LIBRESSL_RIPEMD160";
|
return "POW";
|
||||||
case OP_INI_LOAD: return "INI_LOAD";
|
case OP_RANDOM_SEED:
|
||||||
case OP_INI_FREE: return "INI_FREE";
|
return "RANDOM_SEED";
|
||||||
case OP_INI_GET_STRING: return "INI_GET_STRING";
|
case OP_RANDOM_INT:
|
||||||
case OP_INI_GET_INT: return "INI_GET_INT";
|
return "RANDOM_INT";
|
||||||
case OP_INI_GET_DOUBLE: return "INI_GET_DOUBLE";
|
case OP_MAKE_MAP:
|
||||||
case OP_INI_GET_BOOL: return "INI_GET_BOOL";
|
return "MAKE_MAP";
|
||||||
case OP_INI_SET: return "INI_SET";
|
case OP_KEYS:
|
||||||
case OP_INI_UNSET: return "INI_UNSET";
|
return "KEYS";
|
||||||
case OP_INI_SAVE: return "INI_SAVE";
|
case OP_VALUES:
|
||||||
case OP_XML_PARSE: return "XML_PARSE";
|
return "VALUES";
|
||||||
case OP_XML_ROOT: return "XML_ROOT";
|
case OP_HAS_KEY:
|
||||||
case OP_XML_NAME: return "XML_NAME";
|
return "HAS_KEY";
|
||||||
case OP_XML_TEXT: return "XML_TEXT";
|
case OP_READ_FILE:
|
||||||
case OP_TK_EVAL: return "TK_EVAL";
|
return "READ_FILE";
|
||||||
case OP_TK_RESULT: return "TK_RESULT";
|
case OP_WRITE_FILE:
|
||||||
case OP_TK_LOOP: return "TK_LOOP";
|
return "WRITE_FILE";
|
||||||
case OP_TK_WM_TITLE: return "TK_WM_TITLE";
|
case OP_ENV:
|
||||||
case OP_TK_LABEL: return "TK_LABEL";
|
return "ENV";
|
||||||
case OP_TK_BUTTON: return "TK_BUTTON";
|
case OP_INPUT_LINE:
|
||||||
case OP_TK_PACK: return "TK_PACK";
|
return "INPUT_LINE";
|
||||||
case OP_FLOOR: return "FLOOR";
|
case OP_PROC_RUN:
|
||||||
case OP_CEIL: return "CEIL";
|
return "PROC_RUN";
|
||||||
case OP_TRUNC: return "TRUNC";
|
case OP_PROC_SYSTEM:
|
||||||
case OP_ROUND: return "ROUND";
|
return "PROC_SYSTEM";
|
||||||
case OP_SIN: return "SIN";
|
case OP_TIME_NOW_MS:
|
||||||
case OP_COS: return "COS";
|
return "TIME_NOW_MS";
|
||||||
case OP_TAN: return "TAN";
|
case OP_CLOCK_MONO_MS:
|
||||||
case OP_EXP: return "EXP";
|
return "CLOCK_MONO_MS";
|
||||||
case OP_LOG: return "LOG";
|
case OP_DATE_FORMAT:
|
||||||
case OP_LOG10: return "LOG10";
|
return "DATE_FORMAT";
|
||||||
case OP_SQRT: return "SQRT";
|
case OP_ENV_ALL:
|
||||||
case OP_GCD: return "GCD";
|
return "ENV_ALL";
|
||||||
case OP_LCM: return "LCM";
|
case OP_FUN_VERSION:
|
||||||
case OP_ISQRT: return "ISQRT";
|
return "FUN_VERSION";
|
||||||
case OP_SIGN: return "SIGN";
|
case OP_THREAD_SPAWN:
|
||||||
case OP_FMIN: return "FMIN";
|
return "THREAD_SPAWN";
|
||||||
case OP_FMAX: return "FMAX";
|
case OP_THREAD_JOIN:
|
||||||
case OP_RUST_HELLO: return "RUST_HELLO";
|
return "THREAD_JOIN";
|
||||||
case OP_RUST_HELLO_ARGS: return "RUST_HELLO_ARGS";
|
case OP_SLEEP_MS:
|
||||||
case OP_RUST_HELLO_ARGS_RETURN: return "RUST_HELLO_ARGS_RETURN";
|
return "SLEEP_MS";
|
||||||
case OP_RUST_GET_SP: return "RUST_GET_SP";
|
case OP_RANDOM_NUMBER:
|
||||||
case OP_RUST_SET_EXIT: return "RUST_SET_EXIT";
|
return "RANDOM_NUMBER";
|
||||||
default: return "???";
|
case OP_BAND:
|
||||||
|
return "BAND";
|
||||||
|
case OP_BOR:
|
||||||
|
return "BOR";
|
||||||
|
case OP_BXOR:
|
||||||
|
return "BXOR";
|
||||||
|
case OP_BNOT:
|
||||||
|
return "BNOT";
|
||||||
|
case OP_SHL:
|
||||||
|
return "SHL";
|
||||||
|
case OP_SHR:
|
||||||
|
return "SHR";
|
||||||
|
case OP_ROTL:
|
||||||
|
return "ROTL";
|
||||||
|
case OP_ROTR:
|
||||||
|
return "ROTR";
|
||||||
|
case OP_JSON_PARSE:
|
||||||
|
return "JSON_PARSE";
|
||||||
|
case OP_JSON_STRINGIFY:
|
||||||
|
return "JSON_STRINGIFY";
|
||||||
|
case OP_JSON_FROM_FILE:
|
||||||
|
return "JSON_FROM_FILE";
|
||||||
|
case OP_JSON_TO_FILE:
|
||||||
|
return "JSON_TO_FILE";
|
||||||
|
case OP_CURL_GET:
|
||||||
|
return "CURL_GET";
|
||||||
|
case OP_CURL_POST:
|
||||||
|
return "CURL_POST";
|
||||||
|
case OP_CURL_DOWNLOAD:
|
||||||
|
return "CURL_DOWNLOAD";
|
||||||
|
case OP_SQLITE_OPEN:
|
||||||
|
return "SQLITE_OPEN";
|
||||||
|
case OP_SQLITE_CLOSE:
|
||||||
|
return "SQLITE_CLOSE";
|
||||||
|
case OP_SQLITE_EXEC:
|
||||||
|
return "SQLITE_EXEC";
|
||||||
|
case OP_SQLITE_QUERY:
|
||||||
|
return "SQLITE_QUERY";
|
||||||
|
case OP_LIBSQL_OPEN:
|
||||||
|
return "LIBSQL_OPEN";
|
||||||
|
case OP_LIBSQL_CLOSE:
|
||||||
|
return "LIBSQL_CLOSE";
|
||||||
|
case OP_LIBSQL_EXEC:
|
||||||
|
return "LIBSQL_EXEC";
|
||||||
|
case OP_LIBSQL_QUERY:
|
||||||
|
return "LIBSQL_QUERY";
|
||||||
|
case OP_PCSC_ESTABLISH:
|
||||||
|
return "PCSC_ESTABLISH";
|
||||||
|
case OP_PCSC_RELEASE:
|
||||||
|
return "PCSC_RELEASE";
|
||||||
|
case OP_PCSC_LIST_READERS:
|
||||||
|
return "PCSC_LIST_READERS";
|
||||||
|
case OP_PCSC_CONNECT:
|
||||||
|
return "PCSC_CONNECT";
|
||||||
|
case OP_PCSC_DISCONNECT:
|
||||||
|
return "PCSC_DISCONNECT";
|
||||||
|
case OP_PCSC_TRANSMIT:
|
||||||
|
return "PCSC_TRANSMIT";
|
||||||
|
case OP_PCRE2_TEST:
|
||||||
|
return "PCRE2_TEST";
|
||||||
|
case OP_PCRE2_MATCH:
|
||||||
|
return "PCRE2_MATCH";
|
||||||
|
case OP_PCRE2_FINDALL:
|
||||||
|
return "PCRE2_FINDALL";
|
||||||
|
case OP_OPENSSL_MD5:
|
||||||
|
return "OPENSSL_MD5";
|
||||||
|
case OP_OPENSSL_SHA256:
|
||||||
|
return "OPENSSL_SHA256";
|
||||||
|
case OP_OPENSSL_SHA512:
|
||||||
|
return "OPENSSL_SHA512";
|
||||||
|
case OP_OPENSSL_RIPEMD160:
|
||||||
|
return "OPENSSL_RIPEMD160";
|
||||||
|
case OP_LIBRESSL_MD5:
|
||||||
|
return "LIBRESSL_MD5";
|
||||||
|
case OP_LIBRESSL_SHA256:
|
||||||
|
return "LIBRESSL_SHA256";
|
||||||
|
case OP_LIBRESSL_SHA512:
|
||||||
|
return "LIBRESSL_SHA512";
|
||||||
|
case OP_LIBRESSL_RIPEMD160:
|
||||||
|
return "LIBRESSL_RIPEMD160";
|
||||||
|
case OP_INI_LOAD:
|
||||||
|
return "INI_LOAD";
|
||||||
|
case OP_INI_FREE:
|
||||||
|
return "INI_FREE";
|
||||||
|
case OP_INI_GET_STRING:
|
||||||
|
return "INI_GET_STRING";
|
||||||
|
case OP_INI_GET_INT:
|
||||||
|
return "INI_GET_INT";
|
||||||
|
case OP_INI_GET_DOUBLE:
|
||||||
|
return "INI_GET_DOUBLE";
|
||||||
|
case OP_INI_GET_BOOL:
|
||||||
|
return "INI_GET_BOOL";
|
||||||
|
case OP_INI_SET:
|
||||||
|
return "INI_SET";
|
||||||
|
case OP_INI_UNSET:
|
||||||
|
return "INI_UNSET";
|
||||||
|
case OP_INI_SAVE:
|
||||||
|
return "INI_SAVE";
|
||||||
|
case OP_XML_PARSE:
|
||||||
|
return "XML_PARSE";
|
||||||
|
case OP_XML_ROOT:
|
||||||
|
return "XML_ROOT";
|
||||||
|
case OP_XML_NAME:
|
||||||
|
return "XML_NAME";
|
||||||
|
case OP_XML_TEXT:
|
||||||
|
return "XML_TEXT";
|
||||||
|
case OP_TK_EVAL:
|
||||||
|
return "TK_EVAL";
|
||||||
|
case OP_TK_RESULT:
|
||||||
|
return "TK_RESULT";
|
||||||
|
case OP_TK_LOOP:
|
||||||
|
return "TK_LOOP";
|
||||||
|
case OP_TK_WM_TITLE:
|
||||||
|
return "TK_WM_TITLE";
|
||||||
|
case OP_TK_LABEL:
|
||||||
|
return "TK_LABEL";
|
||||||
|
case OP_TK_BUTTON:
|
||||||
|
return "TK_BUTTON";
|
||||||
|
case OP_TK_PACK:
|
||||||
|
return "TK_PACK";
|
||||||
|
case OP_FLOOR:
|
||||||
|
return "FLOOR";
|
||||||
|
case OP_CEIL:
|
||||||
|
return "CEIL";
|
||||||
|
case OP_TRUNC:
|
||||||
|
return "TRUNC";
|
||||||
|
case OP_ROUND:
|
||||||
|
return "ROUND";
|
||||||
|
case OP_SIN:
|
||||||
|
return "SIN";
|
||||||
|
case OP_COS:
|
||||||
|
return "COS";
|
||||||
|
case OP_TAN:
|
||||||
|
return "TAN";
|
||||||
|
case OP_EXP:
|
||||||
|
return "EXP";
|
||||||
|
case OP_LOG:
|
||||||
|
return "LOG";
|
||||||
|
case OP_LOG10:
|
||||||
|
return "LOG10";
|
||||||
|
case OP_SQRT:
|
||||||
|
return "SQRT";
|
||||||
|
case OP_GCD:
|
||||||
|
return "GCD";
|
||||||
|
case OP_LCM:
|
||||||
|
return "LCM";
|
||||||
|
case OP_ISQRT:
|
||||||
|
return "ISQRT";
|
||||||
|
case OP_SIGN:
|
||||||
|
return "SIGN";
|
||||||
|
case OP_FMIN:
|
||||||
|
return "FMIN";
|
||||||
|
case OP_FMAX:
|
||||||
|
return "FMAX";
|
||||||
|
case OP_RUST_HELLO:
|
||||||
|
return "RUST_HELLO";
|
||||||
|
case OP_RUST_HELLO_ARGS:
|
||||||
|
return "RUST_HELLO_ARGS";
|
||||||
|
case OP_RUST_HELLO_ARGS_RETURN:
|
||||||
|
return "RUST_HELLO_ARGS_RETURN";
|
||||||
|
case OP_RUST_GET_SP:
|
||||||
|
return "RUST_GET_SP";
|
||||||
|
case OP_RUST_SET_EXIT:
|
||||||
|
return "RUST_SET_EXIT";
|
||||||
|
default:
|
||||||
|
return "???";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@
|
||||||
#ifndef FUN_BYTECODE_H
|
#ifndef FUN_BYTECODE_H
|
||||||
#define FUN_BYTECODE_H
|
#define FUN_BYTECODE_H
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
// VM opcodes
|
// VM opcodes
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
|
||||||
9
src/external/curl.c
vendored
9
src/external/curl.c
vendored
|
|
@ -12,14 +12,19 @@
|
||||||
/* Ensure libcurl headers and helpers are defined at file scope (not inside vm_run) */
|
/* Ensure libcurl headers and helpers are defined at file scope (not inside vm_run) */
|
||||||
#ifdef FUN_WITH_CURL
|
#ifdef FUN_WITH_CURL
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
typedef struct { char *d; size_t n; } FunCurlBuf;
|
typedef struct {
|
||||||
|
char *d;
|
||||||
|
size_t n;
|
||||||
|
} FunCurlBuf;
|
||||||
static size_t fun_curl_write_cb(void *ptr, size_t sz, size_t nm, void *ud) {
|
static size_t fun_curl_write_cb(void *ptr, size_t sz, size_t nm, void *ud) {
|
||||||
size_t add = sz * nm;
|
size_t add = sz * nm;
|
||||||
FunCurlBuf *b = (FunCurlBuf *)ud;
|
FunCurlBuf *b = (FunCurlBuf *)ud;
|
||||||
char *p = (char *)realloc(b->d, b->n + add + 1);
|
char *p = (char *)realloc(b->d, b->n + add + 1);
|
||||||
if (!p) return 0;
|
if (!p) return 0;
|
||||||
memcpy(p + b->n, ptr, add);
|
memcpy(p + b->n, ptr, add);
|
||||||
b->d = p; b->n += add; b->d[b->n] = '\0';
|
b->d = p;
|
||||||
|
b->n += add;
|
||||||
|
b->d[b->n] = '\0';
|
||||||
return add;
|
return add;
|
||||||
}
|
}
|
||||||
static size_t fun_curl_file_write_cb(void *ptr, size_t sz, size_t nm, void *ud) {
|
static size_t fun_curl_file_write_cb(void *ptr, size_t sz, size_t nm, void *ud) {
|
||||||
|
|
|
||||||
6
src/external/ini.c
vendored
6
src/external/ini.c
vendored
|
|
@ -12,17 +12,17 @@
|
||||||
#ifdef FUN_WITH_INI
|
#ifdef FUN_WITH_INI
|
||||||
#if defined(__has_include)
|
#if defined(__has_include)
|
||||||
#if __has_include(<iniparser/iniparser.h>)
|
#if __has_include(<iniparser/iniparser.h>)
|
||||||
# include <iniparser/iniparser.h>
|
|
||||||
#include <iniparser/dictionary.h>
|
#include <iniparser/dictionary.h>
|
||||||
|
#include <iniparser/iniparser.h>
|
||||||
#elif __has_include(<iniparser.h>)
|
#elif __has_include(<iniparser.h>)
|
||||||
# include <iniparser.h>
|
|
||||||
#include <dictionary.h>
|
#include <dictionary.h>
|
||||||
|
#include <iniparser.h>
|
||||||
#else
|
#else
|
||||||
#error "iniparser headers not found"
|
#error "iniparser headers not found"
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
# include <iniparser/iniparser.h>
|
|
||||||
#include <iniparser/dictionary.h>
|
#include <iniparser/dictionary.h>
|
||||||
|
#include <iniparser/iniparser.h>
|
||||||
#endif
|
#endif
|
||||||
#include "vm/ini/handles.h"
|
#include "vm/ini/handles.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
33
src/external/json.c
vendored
33
src/external/json.c
vendored
|
|
@ -23,11 +23,16 @@ static Value json_to_fun(json_object *j) {
|
||||||
if (!j) return make_nil();
|
if (!j) return make_nil();
|
||||||
enum json_type t = json_object_get_type(j);
|
enum json_type t = json_object_get_type(j);
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case json_type_null: return make_nil();
|
case json_type_null:
|
||||||
case json_type_boolean: return make_bool(json_object_get_boolean(j));
|
return make_nil();
|
||||||
case json_type_double: return make_float(json_object_get_double(j));
|
case json_type_boolean:
|
||||||
case json_type_int: return make_int((int64_t)json_object_get_int64(j));
|
return make_bool(json_object_get_boolean(j));
|
||||||
case json_type_string: return make_string(json_object_get_string(j));
|
case json_type_double:
|
||||||
|
return make_float(json_object_get_double(j));
|
||||||
|
case json_type_int:
|
||||||
|
return make_int((int64_t)json_object_get_int64(j));
|
||||||
|
case json_type_string:
|
||||||
|
return make_string(json_object_get_string(j));
|
||||||
case json_type_array: {
|
case json_type_array: {
|
||||||
size_t n = json_object_array_length(j);
|
size_t n = json_object_array_length(j);
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
|
|
@ -40,7 +45,8 @@ static Value json_to_fun(json_object *j) {
|
||||||
vals[i] = json_to_fun(item);
|
vals[i] = json_to_fun(item);
|
||||||
}
|
}
|
||||||
Value arr = make_array_from_values(vals, (int)n);
|
Value arr = make_array_from_values(vals, (int)n);
|
||||||
for (size_t i = 0; i < n; ++i) free_value(vals[i]);
|
for (size_t i = 0; i < n; ++i)
|
||||||
|
free_value(vals[i]);
|
||||||
free(vals);
|
free(vals);
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
@ -58,11 +64,16 @@ static Value json_to_fun(json_object *j) {
|
||||||
|
|
||||||
static json_object *fun_to_json(const Value *v) {
|
static json_object *fun_to_json(const Value *v) {
|
||||||
switch (v->type) {
|
switch (v->type) {
|
||||||
case VAL_NIL: return json_object_new_null();
|
case VAL_NIL:
|
||||||
case VAL_BOOL: return json_object_new_boolean(v->i ? 1 : 0);
|
return json_object_new_null();
|
||||||
case VAL_INT: return json_object_new_int64(v->i);
|
case VAL_BOOL:
|
||||||
case VAL_FLOAT: return json_object_new_double(v->d);
|
return json_object_new_boolean(v->i ? 1 : 0);
|
||||||
case VAL_STRING: return json_object_new_string(v->s ? v->s : "");
|
case VAL_INT:
|
||||||
|
return json_object_new_int64(v->i);
|
||||||
|
case VAL_FLOAT:
|
||||||
|
return json_object_new_double(v->d);
|
||||||
|
case VAL_STRING:
|
||||||
|
return json_object_new_string(v->s ? v->s : "");
|
||||||
case VAL_ARRAY: {
|
case VAL_ARRAY: {
|
||||||
json_object *arr = json_object_new_array();
|
json_object *arr = json_object_new_array();
|
||||||
int n = array_length(v);
|
int n = array_length(v);
|
||||||
|
|
|
||||||
40
src/external/libressl.c
vendored
40
src/external/libressl.c
vendored
|
|
@ -49,9 +49,15 @@ static char *fun_libressl_md5_hex(const unsigned char *data, size_t len) {
|
||||||
} else {
|
} else {
|
||||||
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
||||||
}
|
}
|
||||||
if (ok != 1 || (int)out_len != dlen) { free(digest); return NULL; }
|
if (ok != 1 || (int)out_len != dlen) {
|
||||||
|
free(digest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
char *hex = (char *)malloc((size_t)dlen * 2 + 1);
|
char *hex = (char *)malloc((size_t)dlen * 2 + 1);
|
||||||
if (!hex) { free(digest); return NULL; }
|
if (!hex) {
|
||||||
|
free(digest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
for (int i = 0; i < dlen; ++i) {
|
for (int i = 0; i < dlen; ++i) {
|
||||||
hex[2 * i] = hexdig[(digest[i] >> 4) & 0xF];
|
hex[2 * i] = hexdig[(digest[i] >> 4) & 0xF];
|
||||||
hex[2 * i + 1] = hexdig[digest[i] & 0xF];
|
hex[2 * i + 1] = hexdig[digest[i] & 0xF];
|
||||||
|
|
@ -84,9 +90,15 @@ static char *fun_libressl_sha256_hex(const unsigned char *data, size_t len) {
|
||||||
} else {
|
} else {
|
||||||
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
||||||
}
|
}
|
||||||
if (ok != 1 || (int)out_len != dlen) { free(digest); return NULL; }
|
if (ok != 1 || (int)out_len != dlen) {
|
||||||
|
free(digest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
char *hex = (char *)malloc((size_t)dlen * 2 + 1);
|
char *hex = (char *)malloc((size_t)dlen * 2 + 1);
|
||||||
if (!hex) { free(digest); return NULL; }
|
if (!hex) {
|
||||||
|
free(digest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
for (int i = 0; i < dlen; ++i) {
|
for (int i = 0; i < dlen; ++i) {
|
||||||
hex[2 * i] = hexdig[(digest[i] >> 4) & 0xF];
|
hex[2 * i] = hexdig[(digest[i] >> 4) & 0xF];
|
||||||
hex[2 * i + 1] = hexdig[digest[i] & 0xF];
|
hex[2 * i + 1] = hexdig[digest[i] & 0xF];
|
||||||
|
|
@ -119,9 +131,15 @@ static char *fun_libressl_sha512_hex(const unsigned char *data, size_t len) {
|
||||||
} else {
|
} else {
|
||||||
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
||||||
}
|
}
|
||||||
if (ok != 1 || (int)out_len != dlen) { free(digest); return NULL; }
|
if (ok != 1 || (int)out_len != dlen) {
|
||||||
|
free(digest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
char *hex = (char *)malloc((size_t)dlen * 2 + 1);
|
char *hex = (char *)malloc((size_t)dlen * 2 + 1);
|
||||||
if (!hex) { free(digest); return NULL; }
|
if (!hex) {
|
||||||
|
free(digest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
for (int i = 0; i < dlen; ++i) {
|
for (int i = 0; i < dlen; ++i) {
|
||||||
hex[2 * i] = hexdig[(digest[i] >> 4) & 0xF];
|
hex[2 * i] = hexdig[(digest[i] >> 4) & 0xF];
|
||||||
hex[2 * i + 1] = hexdig[digest[i] & 0xF];
|
hex[2 * i + 1] = hexdig[digest[i] & 0xF];
|
||||||
|
|
@ -154,9 +172,15 @@ static char *fun_libressl_ripemd160_hex(const unsigned char *data, size_t len) {
|
||||||
} else {
|
} else {
|
||||||
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
||||||
}
|
}
|
||||||
if (ok != 1 || (int)out_len != dlen) { free(digest); return NULL; }
|
if (ok != 1 || (int)out_len != dlen) {
|
||||||
|
free(digest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
char *hex = (char *)malloc((size_t)dlen * 2 + 1);
|
char *hex = (char *)malloc((size_t)dlen * 2 + 1);
|
||||||
if (!hex) { free(digest); return NULL; }
|
if (!hex) {
|
||||||
|
free(digest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
for (int i = 0; i < dlen; ++i) {
|
for (int i = 0; i < dlen; ++i) {
|
||||||
hex[2 * i] = hexdig[(digest[i] >> 4) & 0xF];
|
hex[2 * i] = hexdig[(digest[i] >> 4) & 0xF];
|
||||||
hex[2 * i + 1] = hexdig[digest[i] & 0xF];
|
hex[2 * i + 1] = hexdig[digest[i] & 0xF];
|
||||||
|
|
|
||||||
9
src/external/libsql.c
vendored
9
src/external/libsql.c
vendored
|
|
@ -10,10 +10,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef FUN_WITH_LIBSQL
|
#ifdef FUN_WITH_LIBSQL
|
||||||
|
#include <sqlite3.h> /* libsql provides a sqlite3-compatible C API */
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <sqlite3.h> /* libsql provides a sqlite3-compatible C API */
|
|
||||||
|
|
||||||
typedef struct LibSqlHandle {
|
typedef struct LibSqlHandle {
|
||||||
int id;
|
int id;
|
||||||
|
|
@ -36,7 +36,10 @@ static LibSqlHandle *libsql_reg_add(sqlite3 *db) {
|
||||||
|
|
||||||
static LibSqlHandle *libsql_reg_get(int id) {
|
static LibSqlHandle *libsql_reg_get(int id) {
|
||||||
LibSqlHandle *p = g_libsql_handles;
|
LibSqlHandle *p = g_libsql_handles;
|
||||||
while (p) { if (p->id == id) return p; p = p->next; }
|
while (p) {
|
||||||
|
if (p->id == id) return p;
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
40
src/external/openssl.c
vendored
40
src/external/openssl.c
vendored
|
|
@ -45,9 +45,15 @@ static char *fun_openssl_md5_hex(const unsigned char *data, size_t len) {
|
||||||
} else {
|
} else {
|
||||||
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
||||||
}
|
}
|
||||||
if (ok != 1 || (int)out_len != dlen) { free(digest); return NULL; }
|
if (ok != 1 || (int)out_len != dlen) {
|
||||||
|
free(digest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
char *hex = (char *)malloc((size_t)dlen * 2 + 1);
|
char *hex = (char *)malloc((size_t)dlen * 2 + 1);
|
||||||
if (!hex) { free(digest); return NULL; }
|
if (!hex) {
|
||||||
|
free(digest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
for (int i = 0; i < dlen; ++i) {
|
for (int i = 0; i < dlen; ++i) {
|
||||||
hex[2 * i] = hexdig[(digest[i] >> 4) & 0xF];
|
hex[2 * i] = hexdig[(digest[i] >> 4) & 0xF];
|
||||||
hex[2 * i + 1] = hexdig[digest[i] & 0xF];
|
hex[2 * i + 1] = hexdig[digest[i] & 0xF];
|
||||||
|
|
@ -81,9 +87,15 @@ static char *fun_openssl_sha256_hex(const unsigned char *data, size_t len) {
|
||||||
} else {
|
} else {
|
||||||
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
||||||
}
|
}
|
||||||
if (ok != 1 || (int)out_len != dlen) { free(digest); return NULL; }
|
if (ok != 1 || (int)out_len != dlen) {
|
||||||
|
free(digest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
char *hex = (char *)malloc((size_t)dlen * 2 + 1);
|
char *hex = (char *)malloc((size_t)dlen * 2 + 1);
|
||||||
if (!hex) { free(digest); return NULL; }
|
if (!hex) {
|
||||||
|
free(digest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
for (int i = 0; i < dlen; ++i) {
|
for (int i = 0; i < dlen; ++i) {
|
||||||
hex[2 * i] = hexdig[(digest[i] >> 4) & 0xF];
|
hex[2 * i] = hexdig[(digest[i] >> 4) & 0xF];
|
||||||
hex[2 * i + 1] = hexdig[digest[i] & 0xF];
|
hex[2 * i + 1] = hexdig[digest[i] & 0xF];
|
||||||
|
|
@ -117,9 +129,15 @@ static char *fun_openssl_sha512_hex(const unsigned char *data, size_t len) {
|
||||||
} else {
|
} else {
|
||||||
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
||||||
}
|
}
|
||||||
if (ok != 1 || (int)out_len != dlen) { free(digest); return NULL; }
|
if (ok != 1 || (int)out_len != dlen) {
|
||||||
|
free(digest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
char *hex = (char *)malloc((size_t)dlen * 2 + 1);
|
char *hex = (char *)malloc((size_t)dlen * 2 + 1);
|
||||||
if (!hex) { free(digest); return NULL; }
|
if (!hex) {
|
||||||
|
free(digest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
for (int i = 0; i < dlen; ++i) {
|
for (int i = 0; i < dlen; ++i) {
|
||||||
hex[2 * i] = hexdig[(digest[i] >> 4) & 0xF];
|
hex[2 * i] = hexdig[(digest[i] >> 4) & 0xF];
|
||||||
hex[2 * i + 1] = hexdig[digest[i] & 0xF];
|
hex[2 * i + 1] = hexdig[digest[i] & 0xF];
|
||||||
|
|
@ -155,9 +173,15 @@ static char *fun_openssl_ripemd160_hex(const unsigned char *data, size_t len) {
|
||||||
} else {
|
} else {
|
||||||
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
||||||
}
|
}
|
||||||
if (ok != 1 || (int)out_len != dlen) { free(digest); return NULL; }
|
if (ok != 1 || (int)out_len != dlen) {
|
||||||
|
free(digest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
char *hex = (char *)malloc((size_t)dlen * 2 + 1);
|
char *hex = (char *)malloc((size_t)dlen * 2 + 1);
|
||||||
if (!hex) { free(digest); return NULL; }
|
if (!hex) {
|
||||||
|
free(digest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
for (int i = 0; i < dlen; ++i) {
|
for (int i = 0; i < dlen; ++i) {
|
||||||
hex[2 * i] = hexdig[(digest[i] >> 4) & 0xF];
|
hex[2 * i] = hexdig[(digest[i] >> 4) & 0xF];
|
||||||
hex[2 * i + 1] = hexdig[digest[i] & 0xF];
|
hex[2 * i + 1] = hexdig[digest[i] & 0xF];
|
||||||
|
|
|
||||||
13
src/external/pcsc.c
vendored
13
src/external/pcsc.c
vendored
|
|
@ -46,14 +46,23 @@ static pcsc_card_entry g_pcsc_card[32];
|
||||||
|
|
||||||
static int pcsc_alloc_ctx_slot(void) {
|
static int pcsc_alloc_ctx_slot(void) {
|
||||||
for (int i = 0; i < (int)(sizeof(g_pcsc_ctx) / sizeof(g_pcsc_ctx[0])); ++i) {
|
for (int i = 0; i < (int)(sizeof(g_pcsc_ctx) / sizeof(g_pcsc_ctx[0])); ++i) {
|
||||||
if (!g_pcsc_ctx[i].in_use) { g_pcsc_ctx[i].in_use = 1; g_pcsc_ctx[i].ctx = 0; return i + 1; }
|
if (!g_pcsc_ctx[i].in_use) {
|
||||||
|
g_pcsc_ctx[i].in_use = 1;
|
||||||
|
g_pcsc_ctx[i].ctx = 0;
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pcsc_alloc_card_slot(void) {
|
static int pcsc_alloc_card_slot(void) {
|
||||||
for (int i = 0; i < (int)(sizeof(g_pcsc_card) / sizeof(g_pcsc_card[0])); ++i) {
|
for (int i = 0; i < (int)(sizeof(g_pcsc_card) / sizeof(g_pcsc_card[0])); ++i) {
|
||||||
if (!g_pcsc_card[i].in_use) { g_pcsc_card[i].in_use = 1; g_pcsc_card[i].h = 0; g_pcsc_card[i].proto = 0; return i + 1; }
|
if (!g_pcsc_card[i].in_use) {
|
||||||
|
g_pcsc_card[i].in_use = 1;
|
||||||
|
g_pcsc_card[i].h = 0;
|
||||||
|
g_pcsc_card[i].proto = 0;
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
src/external/sqlite.c
vendored
10
src/external/sqlite.c
vendored
|
|
@ -35,14 +35,20 @@ static SqlHandle* sql_reg_add(sqlite3 *db) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static SqlHandle *sql_reg_get(int id) {
|
static SqlHandle *sql_reg_get(int id) {
|
||||||
for (SqlHandle *p = g_sql_handles; p; p = p->next) if (p->id == id) return p;
|
for (SqlHandle *p = g_sql_handles; p; p = p->next)
|
||||||
|
if (p->id == id) return p;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sql_reg_del(int id) {
|
static void sql_reg_del(int id) {
|
||||||
SqlHandle **pp = &g_sql_handles;
|
SqlHandle **pp = &g_sql_handles;
|
||||||
while (*pp) {
|
while (*pp) {
|
||||||
if ((*pp)->id == id) { SqlHandle *d = *pp; *pp = d->next; free(d); return; }
|
if ((*pp)->id == id) {
|
||||||
|
SqlHandle *d = *pp;
|
||||||
|
*pp = d->next;
|
||||||
|
free(d);
|
||||||
|
return;
|
||||||
|
}
|
||||||
pp = &(*pp)->next;
|
pp = &(*pp)->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
20
src/external/tcltk.c
vendored
20
src/external/tcltk.c
vendored
|
|
@ -48,7 +48,8 @@ static void fun_tk_loop(void) {
|
||||||
if (!g_fun_tcl_interp) return;
|
if (!g_fun_tcl_interp) return;
|
||||||
/* Drive Tk event loop until all main windows are closed */
|
/* Drive Tk event loop until all main windows are closed */
|
||||||
while (Tk_GetNumMainWindows() > 0) {
|
while (Tk_GetNumMainWindows() > 0) {
|
||||||
while (Tcl_DoOneEvent(0)) {}
|
while (Tcl_DoOneEvent(0)) {
|
||||||
|
}
|
||||||
/* tiny sleep to avoid busy spin */
|
/* tiny sleep to avoid busy spin */
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
@ -62,8 +63,17 @@ static void fun_tk_loop(void) {
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* Stubs when Tcl/Tk is disabled */
|
/* Stubs when Tcl/Tk is disabled */
|
||||||
static void fun_tk_init_once(void) { (void)0; }
|
static void fun_tk_init_once(void) {
|
||||||
static int fun_tk_eval_script(const char *script) { (void)script; return -1; }
|
(void)0;
|
||||||
static const char* fun_tk_get_result(void) { return ""; }
|
}
|
||||||
static void fun_tk_loop(void) { (void)0; }
|
static int fun_tk_eval_script(const char *script) {
|
||||||
|
(void)script;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
static const char *fun_tk_get_result(void) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
static void fun_tk_loop(void) {
|
||||||
|
(void)0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
22
src/external/xml2.c
vendored
22
src/external/xml2.c
vendored
|
|
@ -13,15 +13,25 @@
|
||||||
#include <libxml/parser.h>
|
#include <libxml/parser.h>
|
||||||
#include <libxml/tree.h>
|
#include <libxml/tree.h>
|
||||||
|
|
||||||
typedef struct { xmlDocPtr doc; int in_use; } XmlDocSlot;
|
typedef struct {
|
||||||
typedef struct { xmlNodePtr node; int in_use; } XmlNodeSlot;
|
xmlDocPtr doc;
|
||||||
|
int in_use;
|
||||||
|
} XmlDocSlot;
|
||||||
|
typedef struct {
|
||||||
|
xmlNodePtr node;
|
||||||
|
int in_use;
|
||||||
|
} XmlNodeSlot;
|
||||||
|
|
||||||
static XmlDocSlot g_xml_docs[64];
|
static XmlDocSlot g_xml_docs[64];
|
||||||
static XmlNodeSlot g_xml_nodes[256];
|
static XmlNodeSlot g_xml_nodes[256];
|
||||||
|
|
||||||
static int xml_doc_alloc(xmlDocPtr d) {
|
static int xml_doc_alloc(xmlDocPtr d) {
|
||||||
for (int i = 1; i < (int)(sizeof(g_xml_docs) / sizeof(g_xml_docs[0])); ++i) {
|
for (int i = 1; i < (int)(sizeof(g_xml_docs) / sizeof(g_xml_docs[0])); ++i) {
|
||||||
if (!g_xml_docs[i].in_use) { g_xml_docs[i].in_use = 1; g_xml_docs[i].doc = d; return i; }
|
if (!g_xml_docs[i].in_use) {
|
||||||
|
g_xml_docs[i].in_use = 1;
|
||||||
|
g_xml_docs[i].doc = d;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -39,7 +49,11 @@ static int xml_doc_free_handle(int h) {
|
||||||
|
|
||||||
static int xml_node_alloc(xmlNodePtr n) {
|
static int xml_node_alloc(xmlNodePtr n) {
|
||||||
for (int i = 1; i < (int)(sizeof(g_xml_nodes) / sizeof(g_xml_nodes[0])); ++i) {
|
for (int i = 1; i < (int)(sizeof(g_xml_nodes) / sizeof(g_xml_nodes[0])); ++i) {
|
||||||
if (!g_xml_nodes[i].in_use) { g_xml_nodes[i].in_use = 1; g_xml_nodes[i].node = n; return i; }
|
if (!g_xml_nodes[i].in_use) {
|
||||||
|
g_xml_nodes[i].in_use = 1;
|
||||||
|
g_xml_nodes[i].node = n;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "bytecode.h"
|
#include "bytecode.h"
|
||||||
#include "vm.h"
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "vm.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@
|
||||||
#include "bytecode.h"
|
#include "bytecode.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
#include <stdio.h>
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#define ASSERT_EQ(val, expected) \
|
#define ASSERT_EQ(val, expected) \
|
||||||
if ((val).type != VAL_INT || (val).i != (expected)) { \
|
if ((val).type != VAL_INT || (val).i != (expected)) { \
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ Value bi_enumerate(const Value *arr) {
|
||||||
pairs[i] = kv;
|
pairs[i] = kv;
|
||||||
}
|
}
|
||||||
Value out = make_array_from_values(pairs, n);
|
Value out = make_array_from_values(pairs, n);
|
||||||
for (int i = 0; i < n; ++i) free_value(pairs[i]);
|
for (int i = 0; i < n; ++i)
|
||||||
|
free_value(pairs[i]);
|
||||||
free(pairs);
|
free(pairs);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
@ -54,7 +55,8 @@ Value bi_zip(const Value *a, const Value *b) {
|
||||||
pairs[i] = kv;
|
pairs[i] = kv;
|
||||||
}
|
}
|
||||||
Value out = make_array_from_values(pairs, n);
|
Value out = make_array_from_values(pairs, n);
|
||||||
for (int i = 0; i < n; ++i) free_value(pairs[i]);
|
for (int i = 0; i < n; ++i)
|
||||||
|
free_value(pairs[i]);
|
||||||
free(pairs);
|
free(pairs);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
19
src/map.c
19
src/map.c
|
|
@ -37,7 +37,8 @@ Value make_map_empty(void) {
|
||||||
static int map_ensure_cap(Map *m, int need) {
|
static int map_ensure_cap(Map *m, int need) {
|
||||||
if (m->cap >= need) return 1;
|
if (m->cap >= need) return 1;
|
||||||
int ncap = m->cap == 0 ? 4 : m->cap * 2;
|
int ncap = m->cap == 0 ? 4 : m->cap * 2;
|
||||||
while (ncap < need) ncap *= 2;
|
while (ncap < need)
|
||||||
|
ncap *= 2;
|
||||||
char **nkeys = (char **)realloc(m->keys, sizeof(char *) * ncap);
|
char **nkeys = (char **)realloc(m->keys, sizeof(char *) * ncap);
|
||||||
Value *nvals = (Value *)realloc(m->vals, sizeof(Value) * ncap);
|
Value *nvals = (Value *)realloc(m->vals, sizeof(Value) * ncap);
|
||||||
if (!nkeys || !nvals) return 0;
|
if (!nkeys || !nvals) return 0;
|
||||||
|
|
@ -48,7 +49,10 @@ static int map_ensure_cap(Map *m, int need) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int map_set(Value *vm, const char *key, Value v) {
|
int map_set(Value *vm, const char *key, Value v) {
|
||||||
if (!vm || vm->type != VAL_MAP || !vm->map || !key) { free_value(v); return 0; }
|
if (!vm || vm->type != VAL_MAP || !vm->map || !key) {
|
||||||
|
free_value(v);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Map *m = (Map *)vm->map;
|
Map *m = (Map *)vm->map;
|
||||||
for (int i = 0; i < m->count; ++i) {
|
for (int i = 0; i < m->count; ++i) {
|
||||||
if (strcmp(m->keys[i], key) == 0) {
|
if (strcmp(m->keys[i], key) == 0) {
|
||||||
|
|
@ -57,7 +61,10 @@ int map_set(Value *vm, const char *key, Value v) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!map_ensure_cap(m, m->count + 1)) { free_value(v); return 0; }
|
if (!map_ensure_cap(m, m->count + 1)) {
|
||||||
|
free_value(v);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
m->keys[m->count] = strdup(key);
|
m->keys[m->count] = strdup(key);
|
||||||
m->vals[m->count] = v;
|
m->vals[m->count] = v;
|
||||||
m->count++;
|
m->count++;
|
||||||
|
|
@ -95,7 +102,8 @@ Value map_keys_array(const Value *vm) {
|
||||||
tmp[i] = make_string(m->keys[i]);
|
tmp[i] = make_string(m->keys[i]);
|
||||||
}
|
}
|
||||||
Value arr = make_array_from_values(tmp, m->count);
|
Value arr = make_array_from_values(tmp, m->count);
|
||||||
for (int i = 0; i < m->count; ++i) free_value(tmp[i]);
|
for (int i = 0; i < m->count; ++i)
|
||||||
|
free_value(tmp[i]);
|
||||||
free(tmp);
|
free(tmp);
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
@ -110,7 +118,8 @@ Value map_values_array(const Value *vm) {
|
||||||
tmp[i] = copy_value(&m->vals[i]);
|
tmp[i] = copy_value(&m->vals[i]);
|
||||||
}
|
}
|
||||||
Value arr = make_array_from_values(tmp, m->count);
|
Value arr = make_array_from_values(tmp, m->count);
|
||||||
for (int i = 0; i < m->count; ++i) free_value(tmp[i]);
|
for (int i = 0; i < m->count; ++i)
|
||||||
|
free_value(tmp[i]);
|
||||||
free(tmp);
|
free(tmp);
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3363
src/parser.c
3363
src/parser.c
File diff suppressed because it is too large
Load diff
|
|
@ -7,21 +7,30 @@
|
||||||
* https://opensource.org/license/apache-2-0
|
* https://opensource.org/license/apache-2-0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
|
||||||
#include "parser.h"
|
|
||||||
|
|
||||||
static char *read_file_all(const char *path, size_t *out_len) {
|
static char *read_file_all(const char *path, size_t *out_len) {
|
||||||
FILE *f = fopen(path, "rb");
|
FILE *f = fopen(path, "rb");
|
||||||
if (!f) return NULL;
|
if (!f) return NULL;
|
||||||
if (fseek(f, 0, SEEK_END) != 0) { fclose(f); return NULL; }
|
if (fseek(f, 0, SEEK_END) != 0) {
|
||||||
|
fclose(f);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
long sz = ftell(f);
|
long sz = ftell(f);
|
||||||
if (sz < 0) { fclose(f); return NULL; }
|
if (sz < 0) {
|
||||||
|
fclose(f);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
rewind(f);
|
rewind(f);
|
||||||
char *buf = (char *)malloc((size_t)sz + 1);
|
char *buf = (char *)malloc((size_t)sz + 1);
|
||||||
if (!buf) { fclose(f); return NULL; }
|
if (!buf) {
|
||||||
|
fclose(f);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
size_t n = fread(buf, 1, (size_t)sz, f);
|
size_t n = fread(buf, 1, (size_t)sz, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
buf[n] = '\0';
|
buf[n] = '\0';
|
||||||
|
|
@ -32,13 +41,17 @@ static char *read_file_all(const char *path, size_t *out_len) {
|
||||||
static void skip_ws(const char *src, size_t len, size_t *pos) {
|
static void skip_ws(const char *src, size_t len, size_t *pos) {
|
||||||
while (*pos < len) {
|
while (*pos < len) {
|
||||||
char c = src[*pos];
|
char c = src[*pos];
|
||||||
if (c == ' ' || c == '\t' || c == '\r' || c == '\n') { (*pos)++; continue; }
|
if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
|
||||||
|
(*pos)++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void skip_line(const char *src, size_t len, size_t *pos) {
|
static void skip_line(const char *src, size_t len, size_t *pos) {
|
||||||
while (*pos < len && src[*pos] != '\n') (*pos)++;
|
while (*pos < len && src[*pos] != '\n')
|
||||||
|
(*pos)++;
|
||||||
if (*pos < len && src[*pos] == '\n') (*pos)++;
|
if (*pos < len && src[*pos] == '\n') (*pos)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,7 +65,8 @@ static void skip_comments(const char *src, size_t len, size_t *pos) {
|
||||||
}
|
}
|
||||||
if (*pos + 1 < len && src[*pos] == '/' && src[*pos + 1] == '*') {
|
if (*pos + 1 < len && src[*pos] == '/' && src[*pos + 1] == '*') {
|
||||||
*pos += 2;
|
*pos += 2;
|
||||||
while (*pos + 1 < len && !(src[*pos] == '*' && src[*pos + 1] == '/')) (*pos)++;
|
while (*pos + 1 < len && !(src[*pos] == '*' && src[*pos + 1] == '/'))
|
||||||
|
(*pos)++;
|
||||||
if (*pos + 1 < len) *pos += 2;
|
if (*pos + 1 < len) *pos += 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -76,14 +90,18 @@ static void skip_identifier(const char *src, size_t len, size_t *pos) {
|
||||||
size_t p = *pos;
|
size_t p = *pos;
|
||||||
if (p < len && (isalpha((unsigned char)src[p]) || src[p] == '_')) {
|
if (p < len && (isalpha((unsigned char)src[p]) || src[p] == '_')) {
|
||||||
p++;
|
p++;
|
||||||
while (p < len && (isalnum((unsigned char)src[p]) || src[p] == '_')) p++;
|
while (p < len && (isalnum((unsigned char)src[p]) || src[p] == '_'))
|
||||||
|
p++;
|
||||||
}
|
}
|
||||||
*pos = p;
|
*pos = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int consume_char(const char *src, size_t len, size_t *pos, char expected) {
|
static int consume_char(const char *src, size_t len, size_t *pos, char expected) {
|
||||||
skip_ws(src, len, pos);
|
skip_ws(src, len, pos);
|
||||||
if (*pos < len && src[*pos] == expected) { (*pos)++; return 1; }
|
if (*pos < len && src[*pos] == expected) {
|
||||||
|
(*pos)++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,25 +116,45 @@ static char *parse_string_literal_any_quote(const char *src, size_t len, size_t
|
||||||
if (!out) return NULL;
|
if (!out) return NULL;
|
||||||
while (*pos < len) {
|
while (*pos < len) {
|
||||||
char c = src[*pos];
|
char c = src[*pos];
|
||||||
if (c == quote) { (*pos)++; break; }
|
if (c == quote) {
|
||||||
|
(*pos)++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (c == '\\') {
|
if (c == '\\') {
|
||||||
(*pos)++;
|
(*pos)++;
|
||||||
if (*pos >= len) break;
|
if (*pos >= len) break;
|
||||||
char e = src[*pos];
|
char e = src[*pos];
|
||||||
switch (e) {
|
switch (e) {
|
||||||
case 'n': c = '\n'; break;
|
case 'n':
|
||||||
case 'r': c = '\r'; break;
|
c = '\n';
|
||||||
case 't': c = '\t'; break;
|
break;
|
||||||
case '\\': c = '\\'; break;
|
case 'r':
|
||||||
case '"': c = '"'; break;
|
c = '\r';
|
||||||
case '\'': c = '\''; break;
|
break;
|
||||||
default: c = e; break;
|
case 't':
|
||||||
|
c = '\t';
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
c = '\\';
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
c = '"';
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
c = '\'';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
c = e;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (out_len + 1 >= cap) {
|
if (out_len + 1 >= cap) {
|
||||||
cap *= 2;
|
cap *= 2;
|
||||||
char *tmp = (char *)realloc(out, cap);
|
char *tmp = (char *)realloc(out, cap);
|
||||||
if (!tmp) { free(out); return NULL; }
|
if (!tmp) {
|
||||||
|
free(out);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
out = tmp;
|
out = tmp;
|
||||||
}
|
}
|
||||||
out[out_len++] = c;
|
out[out_len++] = c;
|
||||||
|
|
@ -124,7 +162,10 @@ static char *parse_string_literal_any_quote(const char *src, size_t len, size_t
|
||||||
}
|
}
|
||||||
if (out_len + 1 >= cap) {
|
if (out_len + 1 >= cap) {
|
||||||
char *tmp = (char *)realloc(out, cap + 1);
|
char *tmp = (char *)realloc(out, cap + 1);
|
||||||
if (!tmp) { free(out); return NULL; }
|
if (!tmp) {
|
||||||
|
free(out);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
out = tmp;
|
out = tmp;
|
||||||
}
|
}
|
||||||
out[out_len] = '\0';
|
out[out_len] = '\0';
|
||||||
|
|
@ -136,7 +177,10 @@ static char *parse_string_literal_any_quote(const char *src, size_t len, size_t
|
||||||
static void skip_spaces(const char *src, size_t len, size_t *pos) {
|
static void skip_spaces(const char *src, size_t len, size_t *pos) {
|
||||||
while (*pos < len) {
|
while (*pos < len) {
|
||||||
char c = src[*pos];
|
char c = src[*pos];
|
||||||
if (c == ' ' || c == '\t' || c == '\r') { (*pos)++; continue; }
|
if (c == ' ' || c == '\t' || c == '\r') {
|
||||||
|
(*pos)++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -146,7 +190,8 @@ static int read_identifier_into(const char *src, size_t len, size_t *pos, char *
|
||||||
if (p < len && (isalpha((unsigned char)src[p]) || src[p] == '_')) {
|
if (p < len && (isalpha((unsigned char)src[p]) || src[p] == '_')) {
|
||||||
size_t start = p;
|
size_t start = p;
|
||||||
p++;
|
p++;
|
||||||
while (p < len && (isalnum((unsigned char)src[p]) || src[p] == '_')) p++;
|
while (p < len && (isalnum((unsigned char)src[p]) || src[p] == '_'))
|
||||||
|
p++;
|
||||||
size_t n = p - start;
|
size_t n = p - start;
|
||||||
char *name = (char *)malloc(n + 1);
|
char *name = (char *)malloc(n + 1);
|
||||||
if (!name) return 0;
|
if (!name) return 0;
|
||||||
|
|
@ -167,12 +212,18 @@ static uint64_t parse_int_literal_value(const char *src, size_t len, size_t *pos
|
||||||
if (src[p] == '-') sign = -1;
|
if (src[p] == '-') sign = -1;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
if (p >= len) { *ok = 0; return 0; }
|
if (p >= len) {
|
||||||
|
*ok = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Hexadecimal: 0x... or 0X... */
|
/* Hexadecimal: 0x... or 0X... */
|
||||||
if ((p + 1) < len && src[p] == '0' && (src[p + 1] == 'x' || src[p + 1] == 'X')) {
|
if ((p + 1) < len && src[p] == '0' && (src[p + 1] == 'x' || src[p + 1] == 'X')) {
|
||||||
p += 2;
|
p += 2;
|
||||||
if (p >= len || !isxdigit((unsigned char)src[p])) { *ok = 0; return 0; }
|
if (p >= len || !isxdigit((unsigned char)src[p])) {
|
||||||
|
*ok = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
uint64_t val = 0;
|
uint64_t val = 0;
|
||||||
while (p < len && isxdigit((unsigned char)src[p])) {
|
while (p < len && isxdigit((unsigned char)src[p])) {
|
||||||
char c = src[p];
|
char c = src[p];
|
||||||
|
|
@ -189,7 +240,10 @@ static uint64_t parse_int_literal_value(const char *src, size_t len, size_t *pos
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decimal fallback */
|
/* Decimal fallback */
|
||||||
if (!isdigit((unsigned char)src[p])) { *ok = 0; return 0; }
|
if (!isdigit((unsigned char)src[p])) {
|
||||||
|
*ok = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
uint64_t val = 0;
|
uint64_t val = 0;
|
||||||
while (p < len && isdigit((unsigned char)src[p])) {
|
while (p < len && isdigit((unsigned char)src[p])) {
|
||||||
val = val * 10 + (uint64_t)(src[p] - '0');
|
val = val * 10 + (uint64_t)(src[p] - '0');
|
||||||
|
|
@ -229,7 +283,8 @@ static void sb_init(StrBuf *sb) {
|
||||||
static void sb_reserve(StrBuf *sb, size_t need) {
|
static void sb_reserve(StrBuf *sb, size_t need) {
|
||||||
if (need <= sb->cap) return;
|
if (need <= sb->cap) return;
|
||||||
size_t nc = sb->cap ? sb->cap : 256;
|
size_t nc = sb->cap ? sb->cap : 256;
|
||||||
while (nc < need) nc *= 2;
|
while (nc < need)
|
||||||
|
nc *= 2;
|
||||||
char *nb = (char *)xrealloc(sb->buf, nc);
|
char *nb = (char *)xrealloc(sb->buf, nc);
|
||||||
if (!nb) return;
|
if (!nb) return;
|
||||||
sb->buf = nb;
|
sb->buf = nb;
|
||||||
|
|
@ -283,7 +338,8 @@ static void nl_add(NameList *nl, const char *name) {
|
||||||
|
|
||||||
static void nl_free(NameList *nl) {
|
static void nl_free(NameList *nl) {
|
||||||
if (!nl) return;
|
if (!nl) return;
|
||||||
for (int i = 0; i < nl->count; ++i) free(nl->names[i]);
|
for (int i = 0; i < nl->count; ++i)
|
||||||
|
free(nl->names[i]);
|
||||||
free(nl->names);
|
free(nl->names);
|
||||||
nl->names = NULL;
|
nl->names = NULL;
|
||||||
nl->count = nl->cap = 0;
|
nl->count = nl->cap = 0;
|
||||||
|
|
@ -300,8 +356,12 @@ static void collect_exports_top_level(const char *text, NameList *out) {
|
||||||
char c = text[i];
|
char c = text[i];
|
||||||
|
|
||||||
if (in_line) {
|
if (in_line) {
|
||||||
if (c == '\n') { in_line = 0; bol = 1; }
|
if (c == '\n') {
|
||||||
else { bol = 0; }
|
in_line = 0;
|
||||||
|
bol = 1;
|
||||||
|
} else {
|
||||||
|
bol = 0;
|
||||||
|
}
|
||||||
i++;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -317,16 +377,30 @@ static void collect_exports_top_level(const char *text, NameList *out) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (in_sq) {
|
if (in_sq) {
|
||||||
if (!esc && c == '\\') { esc = 1; i++; bol = 0; continue; }
|
if (!esc && c == '\\') {
|
||||||
if (!esc && c == '\'') { in_sq = 0; }
|
esc = 1;
|
||||||
|
i++;
|
||||||
|
bol = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!esc && c == '\'') {
|
||||||
|
in_sq = 0;
|
||||||
|
}
|
||||||
esc = 0;
|
esc = 0;
|
||||||
bol = (c == '\n');
|
bol = (c == '\n');
|
||||||
i++;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (in_dq) {
|
if (in_dq) {
|
||||||
if (!esc && c == '\\') { esc = 1; i++; bol = 0; continue; }
|
if (!esc && c == '\\') {
|
||||||
if (!esc && c == '"') { in_dq = 0; }
|
esc = 1;
|
||||||
|
i++;
|
||||||
|
bol = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!esc && c == '"') {
|
||||||
|
in_dq = 0;
|
||||||
|
}
|
||||||
esc = 0;
|
esc = 0;
|
||||||
bol = (c == '\n');
|
bol = (c == '\n');
|
||||||
i++;
|
i++;
|
||||||
|
|
@ -345,14 +419,27 @@ static void collect_exports_top_level(const char *text, NameList *out) {
|
||||||
i += 2;
|
i += 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (c == '\'') { in_sq = 1; bol = 0; i++; continue; }
|
if (c == '\'') {
|
||||||
if (c == '"') { in_dq = 1; bol = 0; i++; continue; }
|
in_sq = 1;
|
||||||
|
bol = 0;
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == '"') {
|
||||||
|
in_dq = 1;
|
||||||
|
bol = 0;
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (bol) {
|
if (bol) {
|
||||||
/* Compute leading spaces to filter out indented constructs */
|
/* Compute leading spaces to filter out indented constructs */
|
||||||
size_t j = i;
|
size_t j = i;
|
||||||
int spaces = 0;
|
int spaces = 0;
|
||||||
while (j < len && text[j] == ' ') { spaces++; j++; }
|
while (j < len && text[j] == ' ') {
|
||||||
|
spaces++;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
if (j < len && text[j] == '\t') {
|
if (j < len && text[j] == '\t') {
|
||||||
/* tabs not allowed for indentation; treat as not top-level */
|
/* tabs not allowed for indentation; treat as not top-level */
|
||||||
bol = 0;
|
bol = 0;
|
||||||
|
|
@ -366,12 +453,14 @@ static void collect_exports_top_level(const char *text, NameList *out) {
|
||||||
const char *kw2 = "class";
|
const char *kw2 = "class";
|
||||||
if (j + 3 <= len && strncmp(text + j, kw1, 3) == 0 && (j + 3 == len || isspace((unsigned char)text[j + 3]))) {
|
if (j + 3 <= len && strncmp(text + j, kw1, 3) == 0 && (j + 3 == len || isspace((unsigned char)text[j + 3]))) {
|
||||||
size_t p = j + 3;
|
size_t p = j + 3;
|
||||||
while (p < len && (text[p] == ' ' || text[p] == '\t')) p++;
|
while (p < len && (text[p] == ' ' || text[p] == '\t'))
|
||||||
|
p++;
|
||||||
/* read identifier */
|
/* read identifier */
|
||||||
size_t start = p;
|
size_t start = p;
|
||||||
if (p < len && (isalpha((unsigned char)text[p]) || text[p] == '_')) {
|
if (p < len && (isalpha((unsigned char)text[p]) || text[p] == '_')) {
|
||||||
p++;
|
p++;
|
||||||
while (p < len && (isalnum((unsigned char)text[p]) || text[p] == '_')) p++;
|
while (p < len && (isalnum((unsigned char)text[p]) || text[p] == '_'))
|
||||||
|
p++;
|
||||||
size_t n = p - start;
|
size_t n = p - start;
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
char tmp[256];
|
char tmp[256];
|
||||||
|
|
@ -383,12 +472,14 @@ static void collect_exports_top_level(const char *text, NameList *out) {
|
||||||
}
|
}
|
||||||
} else if (j + 5 <= len && strncmp(text + j, kw2, 5) == 0 && (j + 5 == len || isspace((unsigned char)text[j + 5]))) {
|
} else if (j + 5 <= len && strncmp(text + j, kw2, 5) == 0 && (j + 5 == len || isspace((unsigned char)text[j + 5]))) {
|
||||||
size_t p = j + 5;
|
size_t p = j + 5;
|
||||||
while (p < len && (text[p] == ' ' || text[p] == '\t')) p++;
|
while (p < len && (text[p] == ' ' || text[p] == '\t'))
|
||||||
|
p++;
|
||||||
/* read identifier */
|
/* read identifier */
|
||||||
size_t start = p;
|
size_t start = p;
|
||||||
if (p < len && (isalpha((unsigned char)text[p]) || text[p] == '_')) {
|
if (p < len && (isalpha((unsigned char)text[p]) || text[p] == '_')) {
|
||||||
p++;
|
p++;
|
||||||
while (p < len && (isalnum((unsigned char)text[p]) || text[p] == '_')) p++;
|
while (p < len && (isalnum((unsigned char)text[p]) || text[p] == '_'))
|
||||||
|
p++;
|
||||||
size_t n = p - start;
|
size_t n = p - start;
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
char tmp[256];
|
char tmp[256];
|
||||||
|
|
@ -434,7 +525,8 @@ static char *preprocess_includes_internal(const char *src, int depth) {
|
||||||
if (bol && !in_block && !in_sq && !in_dq) {
|
if (bol && !in_block && !in_sq && !in_dq) {
|
||||||
size_t j = i;
|
size_t j = i;
|
||||||
/* skip leading spaces/tabs */
|
/* skip leading spaces/tabs */
|
||||||
while (j < len && (src[j] == ' ' || src[j] == '\t')) j++;
|
while (j < len && (src[j] == ' ' || src[j] == '\t'))
|
||||||
|
j++;
|
||||||
size_t k = j;
|
size_t k = j;
|
||||||
if (k < len && src[k] == '#') k++;
|
if (k < len && src[k] == '#') k++;
|
||||||
const char *kw = "include";
|
const char *kw = "include";
|
||||||
|
|
@ -442,13 +534,15 @@ static char *preprocess_includes_internal(const char *src, int depth) {
|
||||||
if (k + kwlen <= len && strncmp(src + k, kw, kwlen) == 0) {
|
if (k + kwlen <= len && strncmp(src + k, kw, kwlen) == 0) {
|
||||||
k += kwlen;
|
k += kwlen;
|
||||||
/* next must be space/tab or delimiter */
|
/* next must be space/tab or delimiter */
|
||||||
while (k < len && (src[k] == ' ' || src[k] == '\t')) k++;
|
while (k < len && (src[k] == ' ' || src[k] == '\t'))
|
||||||
|
k++;
|
||||||
if (k < len && (src[k] == '"' || src[k] == '<')) {
|
if (k < len && (src[k] == '"' || src[k] == '<')) {
|
||||||
char opener = src[k];
|
char opener = src[k];
|
||||||
char closer = (opener == '"') ? '"' : '>';
|
char closer = (opener == '"') ? '"' : '>';
|
||||||
k++;
|
k++;
|
||||||
size_t path_start = k;
|
size_t path_start = k;
|
||||||
while (k < len && src[k] != closer) k++;
|
while (k < len && src[k] != closer)
|
||||||
|
k++;
|
||||||
if (k < len && src[k] == closer) {
|
if (k < len && src[k] == closer) {
|
||||||
size_t path_len = k - path_start;
|
size_t path_len = k - path_start;
|
||||||
char *path = (char *)malloc(path_len + 1);
|
char *path = (char *)malloc(path_len + 1);
|
||||||
|
|
@ -458,20 +552,24 @@ static char *preprocess_includes_internal(const char *src, int depth) {
|
||||||
|
|
||||||
/* parse optional 'as <alias>' then advance to end of line */
|
/* parse optional 'as <alias>' then advance to end of line */
|
||||||
k++;
|
k++;
|
||||||
char ns[64]; ns[0] = '\0';
|
char ns[64];
|
||||||
|
ns[0] = '\0';
|
||||||
/* skip spaces/tabs */
|
/* skip spaces/tabs */
|
||||||
size_t ap = k;
|
size_t ap = k;
|
||||||
while (ap < len && (src[ap] == ' ' || src[ap] == '\t')) ap++;
|
while (ap < len && (src[ap] == ' ' || src[ap] == '\t'))
|
||||||
|
ap++;
|
||||||
/* optional 'as' */
|
/* optional 'as' */
|
||||||
const char *askw = "as";
|
const char *askw = "as";
|
||||||
if (ap + 2 <= len && strncmp(src + ap, askw, 2) == 0 && (ap + 2 == len || isspace((unsigned char)src[ap + 2]))) {
|
if (ap + 2 <= len && strncmp(src + ap, askw, 2) == 0 && (ap + 2 == len || isspace((unsigned char)src[ap + 2]))) {
|
||||||
ap += 2;
|
ap += 2;
|
||||||
while (ap < len && (src[ap] == ' ' || src[ap] == '\t')) ap++;
|
while (ap < len && (src[ap] == ' ' || src[ap] == '\t'))
|
||||||
|
ap++;
|
||||||
/* read identifier [A-Za-z_][A-Za-z0-9_]* */
|
/* read identifier [A-Za-z_][A-Za-z0-9_]* */
|
||||||
size_t start = ap;
|
size_t start = ap;
|
||||||
if (ap < len && (isalpha((unsigned char)src[ap]) || src[ap] == '_')) {
|
if (ap < len && (isalpha((unsigned char)src[ap]) || src[ap] == '_')) {
|
||||||
ap++;
|
ap++;
|
||||||
while (ap < len && (isalnum((unsigned char)src[ap]) || src[ap] == '_')) ap++;
|
while (ap < len && (isalnum((unsigned char)src[ap]) || src[ap] == '_'))
|
||||||
|
ap++;
|
||||||
size_t n = ap - start;
|
size_t n = ap - start;
|
||||||
size_t copy = (n < sizeof(ns) - 1) ? n : (sizeof(ns) - 1);
|
size_t copy = (n < sizeof(ns) - 1) ? n : (sizeof(ns) - 1);
|
||||||
memcpy(ns, src + start, copy);
|
memcpy(ns, src + start, copy);
|
||||||
|
|
@ -481,7 +579,8 @@ static char *preprocess_includes_internal(const char *src, int depth) {
|
||||||
}
|
}
|
||||||
/* advance to end of line */
|
/* advance to end of line */
|
||||||
k = ap;
|
k = ap;
|
||||||
while (k < len && src[k] != '\n') k++;
|
while (k < len && src[k] != '\n')
|
||||||
|
k++;
|
||||||
if (k < len && src[k] == '\n') k++;
|
if (k < len && src[k] == '\n') k++;
|
||||||
|
|
||||||
/* resolve file path; for <...> try FUN_LIB_DIR first, then default */
|
/* resolve file path; for <...> try FUN_LIB_DIR first, then default */
|
||||||
|
|
@ -547,9 +646,14 @@ static char *preprocess_includes_internal(const char *src, int depth) {
|
||||||
if (startp[0] == '#' && startp[1] == '!') {
|
if (startp[0] == '#' && startp[1] == '!') {
|
||||||
/* skip until end of line, handling CR, LF, CRLF */
|
/* skip until end of line, handling CR, LF, CRLF */
|
||||||
const char *q = startp;
|
const char *q = startp;
|
||||||
while (*q && *q != '\n' && *q != '\r') q++;
|
while (*q && *q != '\n' && *q != '\r')
|
||||||
if (*q == '\r') { q++; if (*q == '\n') q++; }
|
q++;
|
||||||
else if (*q == '\n') { q++; }
|
if (*q == '\r') {
|
||||||
|
q++;
|
||||||
|
if (*q == '\n') q++;
|
||||||
|
} else if (*q == '\n') {
|
||||||
|
q++;
|
||||||
|
}
|
||||||
startp = q;
|
startp = q;
|
||||||
}
|
}
|
||||||
char *inc_clean = strdup(startp);
|
char *inc_clean = strdup(startp);
|
||||||
|
|
@ -584,7 +688,8 @@ static char *preprocess_includes_internal(const char *src, int depth) {
|
||||||
|
|
||||||
/* If alias is present, export top-level fun/class into alias map */
|
/* If alias is present, export top-level fun/class into alias map */
|
||||||
if (ns[0] != '\0') {
|
if (ns[0] != '\0') {
|
||||||
NameList nl; nl_init(&nl);
|
NameList nl;
|
||||||
|
nl_init(&nl);
|
||||||
collect_exports_top_level(exp, &nl);
|
collect_exports_top_level(exp, &nl);
|
||||||
for (int ei = 0; ei < nl.count; ++ei) {
|
for (int ei = 0; ei < nl.count; ++ei) {
|
||||||
sb_append(&out, ns);
|
sb_append(&out, ns);
|
||||||
|
|
@ -614,7 +719,12 @@ static char *preprocess_includes_internal(const char *src, int depth) {
|
||||||
/* normal stateful copy with comment/string tracking */
|
/* normal stateful copy with comment/string tracking */
|
||||||
if (in_line) {
|
if (in_line) {
|
||||||
sb_append_ch(&out, c);
|
sb_append_ch(&out, c);
|
||||||
if (c == '\n') { in_line = 0; bol = 1; } else { bol = 0; }
|
if (c == '\n') {
|
||||||
|
in_line = 0;
|
||||||
|
bol = 1;
|
||||||
|
} else {
|
||||||
|
bol = 0;
|
||||||
|
}
|
||||||
i++;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -633,8 +743,15 @@ static char *preprocess_includes_internal(const char *src, int depth) {
|
||||||
}
|
}
|
||||||
if (in_sq) {
|
if (in_sq) {
|
||||||
sb_append_ch(&out, c);
|
sb_append_ch(&out, c);
|
||||||
if (!esc && c == '\\') { esc = 1; i++; bol = 0; continue; }
|
if (!esc && c == '\\') {
|
||||||
if (!esc && c == '\'') { in_sq = 0; }
|
esc = 1;
|
||||||
|
i++;
|
||||||
|
bol = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!esc && c == '\'') {
|
||||||
|
in_sq = 0;
|
||||||
|
}
|
||||||
esc = 0;
|
esc = 0;
|
||||||
bol = (c == '\n') ? 1 : 0;
|
bol = (c == '\n') ? 1 : 0;
|
||||||
i++;
|
i++;
|
||||||
|
|
@ -642,8 +759,15 @@ static char *preprocess_includes_internal(const char *src, int depth) {
|
||||||
}
|
}
|
||||||
if (in_dq) {
|
if (in_dq) {
|
||||||
sb_append_ch(&out, c);
|
sb_append_ch(&out, c);
|
||||||
if (!esc && c == '\\') { esc = 1; i++; bol = 0; continue; }
|
if (!esc && c == '\\') {
|
||||||
if (!esc && c == '"') { in_dq = 0; }
|
esc = 1;
|
||||||
|
i++;
|
||||||
|
bol = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!esc && c == '"') {
|
||||||
|
in_dq = 0;
|
||||||
|
}
|
||||||
esc = 0;
|
esc = 0;
|
||||||
bol = (c == '\n') ? 1 : 0;
|
bol = (c == '\n') ? 1 : 0;
|
||||||
i++;
|
i++;
|
||||||
|
|
@ -698,7 +822,6 @@ char *preprocess_includes(const char *src) {
|
||||||
return preprocess_includes_internal(src, 0);
|
return preprocess_includes_internal(src, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Float literal parser: supports decimal and scientific notation. Returns parsed double and advances pos on success. */
|
/* Float literal parser: supports decimal and scientific notation. Returns parsed double and advances pos on success. */
|
||||||
static double parse_float_literal_value(const char *src, size_t len, size_t *pos, int *ok) {
|
static double parse_float_literal_value(const char *src, size_t len, size_t *pos, int *ok) {
|
||||||
size_t p = *pos;
|
size_t p = *pos;
|
||||||
|
|
@ -712,13 +835,19 @@ static double parse_float_literal_value(const char *src, size_t len, size_t *pos
|
||||||
if (p < len && (src[p] == '+' || src[p] == '-')) p++;
|
if (p < len && (src[p] == '+' || src[p] == '-')) p++;
|
||||||
|
|
||||||
/* integer part */
|
/* integer part */
|
||||||
while (p < len && isdigit((unsigned char)src[p])) { p++; saw_digit = 1; }
|
while (p < len && isdigit((unsigned char)src[p])) {
|
||||||
|
p++;
|
||||||
|
saw_digit = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* fractional part */
|
/* fractional part */
|
||||||
if (p < len && src[p] == '.') {
|
if (p < len && src[p] == '.') {
|
||||||
saw_dot = 1;
|
saw_dot = 1;
|
||||||
p++;
|
p++;
|
||||||
while (p < len && isdigit((unsigned char)src[p])) { p++; saw_digit = 1; }
|
while (p < len && isdigit((unsigned char)src[p])) {
|
||||||
|
p++;
|
||||||
|
saw_digit = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* exponent part */
|
/* exponent part */
|
||||||
|
|
@ -727,28 +856,39 @@ static double parse_float_literal_value(const char *src, size_t len, size_t *pos
|
||||||
size_t epos = p + 1;
|
size_t epos = p + 1;
|
||||||
if (epos < len && (src[epos] == '+' || src[epos] == '-')) epos++;
|
if (epos < len && (src[epos] == '+' || src[epos] == '-')) epos++;
|
||||||
size_t digits_start = epos;
|
size_t digits_start = epos;
|
||||||
while (epos < len && isdigit((unsigned char)src[epos])) { epos++; }
|
while (epos < len && isdigit((unsigned char)src[epos])) {
|
||||||
|
epos++;
|
||||||
|
}
|
||||||
if (epos == digits_start) {
|
if (epos == digits_start) {
|
||||||
/* no digits after exponent -> not a float */
|
/* no digits after exponent -> not a float */
|
||||||
*ok = 0; return 0.0;
|
*ok = 0;
|
||||||
|
return 0.0;
|
||||||
}
|
}
|
||||||
p = epos;
|
p = epos;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!saw_digit || (!saw_dot && !saw_exp)) {
|
if (!saw_digit || (!saw_dot && !saw_exp)) {
|
||||||
*ok = 0; return 0.0;
|
*ok = 0;
|
||||||
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create temporary buffer to parse with strtod safely */
|
/* Create temporary buffer to parse with strtod safely */
|
||||||
size_t n = p - start;
|
size_t n = p - start;
|
||||||
char *tmp = (char *)malloc(n + 1);
|
char *tmp = (char *)malloc(n + 1);
|
||||||
if (!tmp) { *ok = 0; return 0.0; }
|
if (!tmp) {
|
||||||
|
*ok = 0;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
memcpy(tmp, src + start, n);
|
memcpy(tmp, src + start, n);
|
||||||
tmp[n] = '\0';
|
tmp[n] = '\0';
|
||||||
|
|
||||||
char *endp = NULL;
|
char *endp = NULL;
|
||||||
double dv = strtod(tmp, &endp);
|
double dv = strtod(tmp, &endp);
|
||||||
if (!endp || *endp != '\0') { free(tmp); *ok = 0; return 0.0; }
|
if (!endp || *endp != '\0') {
|
||||||
|
free(tmp);
|
||||||
|
*ok = 0;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
*pos = p;
|
*pos = p;
|
||||||
*ok = 1;
|
*ok = 1;
|
||||||
|
|
|
||||||
616
src/repl.c
616
src/repl.c
File diff suppressed because it is too large
Load diff
|
|
@ -49,7 +49,8 @@ Value string_split_to_array(const char *s, const char *sep) {
|
||||||
tmp[i] = make_string(ch);
|
tmp[i] = make_string(ch);
|
||||||
}
|
}
|
||||||
Value arr = make_array_from_values(tmp, n);
|
Value arr = make_array_from_values(tmp, n);
|
||||||
for (int i = 0; i < n; ++i) free_value(tmp[i]);
|
for (int i = 0; i < n; ++i)
|
||||||
|
free_value(tmp[i]);
|
||||||
free(tmp);
|
free(tmp);
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
@ -83,7 +84,8 @@ Value string_split_to_array(const char *s, const char *sep) {
|
||||||
free(tail);
|
free(tail);
|
||||||
|
|
||||||
Value arr = make_array_from_values(parts, count);
|
Value arr = make_array_from_values(parts, count);
|
||||||
for (int i = 0; i < count; ++i) free_value(parts[i]);
|
for (int i = 0; i < count; ++i)
|
||||||
|
free_value(parts[i]);
|
||||||
free(parts);
|
free(parts);
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +115,8 @@ char *array_join_with_sep(const Value *v, const char *sep) {
|
||||||
|
|
||||||
char *out = (char *)malloc(total + 1);
|
char *out = (char *)malloc(total + 1);
|
||||||
if (!out) {
|
if (!out) {
|
||||||
for (int i = 0; i < n; ++i) free(parts[i]);
|
for (int i = 0; i < n; ++i)
|
||||||
|
free(parts[i]);
|
||||||
free(parts);
|
free(parts);
|
||||||
return strdup("");
|
return strdup("");
|
||||||
}
|
}
|
||||||
|
|
@ -121,10 +124,12 @@ char *array_join_with_sep(const Value *v, const char *sep) {
|
||||||
size_t off = 0;
|
size_t off = 0;
|
||||||
for (int i = 0; i < n; ++i) {
|
for (int i = 0; i < n; ++i) {
|
||||||
size_t li = strlen(parts[i]);
|
size_t li = strlen(parts[i]);
|
||||||
memcpy(out + off, parts[i], li); off += li;
|
memcpy(out + off, parts[i], li);
|
||||||
|
off += li;
|
||||||
if (i + 1 < n) {
|
if (i + 1 < n) {
|
||||||
size_t ls = strlen(sep);
|
size_t ls = strlen(sep);
|
||||||
memcpy(out + off, sep, ls); off += ls;
|
memcpy(out + off, sep, ls);
|
||||||
|
off += ls;
|
||||||
}
|
}
|
||||||
free(parts[i]);
|
free(parts[i]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@
|
||||||
* https://opensource.org/license/apache-2-0
|
* https://opensource.org/license/apache-2-0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "vm.h"
|
|
||||||
#include "bytecode.h"
|
#include "bytecode.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
#include "vm.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|
|
||||||
51
src/value.c
51
src/value.c
|
|
@ -8,13 +8,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
/* Compile helper implementations into this TU to avoid build system changes */
|
/* Compile helper implementations into this TU to avoid build system changes */
|
||||||
#include "str_utils.c"
|
|
||||||
#include "array_utils.c"
|
#include "array_utils.c"
|
||||||
|
#include "str_utils.c"
|
||||||
|
|
||||||
typedef struct Array {
|
typedef struct Array {
|
||||||
int refcount;
|
int refcount;
|
||||||
|
|
@ -54,8 +54,10 @@ Value make_bool(int v) {
|
||||||
Value make_string(const char *s) {
|
Value make_string(const char *s) {
|
||||||
Value val;
|
Value val;
|
||||||
val.type = VAL_STRING;
|
val.type = VAL_STRING;
|
||||||
if (s) val.s = strdup(s);
|
if (s)
|
||||||
else val.s = strdup("");
|
val.s = strdup(s);
|
||||||
|
else
|
||||||
|
val.s = strdup("");
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,7 +74,6 @@ Value make_nil(void) {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Value make_array_from_values(const Value *vals, int count) {
|
Value make_array_from_values(const Value *vals, int count) {
|
||||||
if (count < 0) count = 0;
|
if (count < 0) count = 0;
|
||||||
Array *arr = (Array *)malloc(sizeof(Array));
|
Array *arr = (Array *)malloc(sizeof(Array));
|
||||||
|
|
@ -130,7 +131,8 @@ static int ensure_array_capacity(Array *a, int newCount) {
|
||||||
int curr = a->count;
|
int curr = a->count;
|
||||||
int cap = curr;
|
int cap = curr;
|
||||||
if (cap < 4) cap = 4;
|
if (cap < 4) cap = 4;
|
||||||
while (cap < newCount) cap *= 2;
|
while (cap < newCount)
|
||||||
|
cap *= 2;
|
||||||
Value *newItems = (Value *)realloc(a->items, sizeof(Value) * cap);
|
Value *newItems = (Value *)realloc(a->items, sizeof(Value) * cap);
|
||||||
if (!newItems) return 0;
|
if (!newItems) return 0;
|
||||||
/* if growing beyond current count, initialize new slots to nil */
|
/* if growing beyond current count, initialize new slots to nil */
|
||||||
|
|
@ -148,7 +150,10 @@ int array_push(Value *v, Value newElem) {
|
||||||
Array *a = (Array *)v->arr;
|
Array *a = (Array *)v->arr;
|
||||||
/* ensure capacity for count+1 by reallocating items array to at least count+1 elements */
|
/* ensure capacity for count+1 by reallocating items array to at least count+1 elements */
|
||||||
Value *newItems = (Value *)realloc(a->items, sizeof(Value) * (a->count + 1));
|
Value *newItems = (Value *)realloc(a->items, sizeof(Value) * (a->count + 1));
|
||||||
if (!newItems) { free_value(newElem); return -1; }
|
if (!newItems) {
|
||||||
|
free_value(newElem);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
a->items = newItems;
|
a->items = newItems;
|
||||||
a->items[a->count] = newElem; /* take ownership */
|
a->items[a->count] = newElem; /* take ownership */
|
||||||
a->count += 1;
|
a->count += 1;
|
||||||
|
|
@ -160,8 +165,10 @@ int array_pop(Value *v, Value *out) {
|
||||||
Array *a = (Array *)v->arr;
|
Array *a = (Array *)v->arr;
|
||||||
if (a->count <= 0) return 0;
|
if (a->count <= 0) return 0;
|
||||||
int idx = a->count - 1;
|
int idx = a->count - 1;
|
||||||
if (out) *out = a->items[idx]; /* transfer ownership */
|
if (out)
|
||||||
else free_value(a->items[idx]);
|
*out = a->items[idx]; /* transfer ownership */
|
||||||
|
else
|
||||||
|
free_value(a->items[idx]);
|
||||||
a->count -= 1;
|
a->count -= 1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -172,7 +179,10 @@ int array_insert(Value *v, int index, Value newElem) {
|
||||||
if (index < 0) index = 0;
|
if (index < 0) index = 0;
|
||||||
if (index > a->count) index = a->count;
|
if (index > a->count) index = a->count;
|
||||||
Value *newItems = (Value *)realloc(a->items, sizeof(Value) * (a->count + 1));
|
Value *newItems = (Value *)realloc(a->items, sizeof(Value) * (a->count + 1));
|
||||||
if (!newItems) { free_value(newElem); return -1; }
|
if (!newItems) {
|
||||||
|
free_value(newElem);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
a->items = newItems;
|
a->items = newItems;
|
||||||
/* shift right */
|
/* shift right */
|
||||||
for (int i = a->count; i > index; --i) {
|
for (int i = a->count; i > index; --i) {
|
||||||
|
|
@ -187,8 +197,10 @@ int array_remove(Value *v, int index, Value *out) {
|
||||||
if (!v || v->type != VAL_ARRAY || !v->arr) return 0;
|
if (!v || v->type != VAL_ARRAY || !v->arr) return 0;
|
||||||
Array *a = (Array *)v->arr;
|
Array *a = (Array *)v->arr;
|
||||||
if (index < 0 || index >= a->count) return 0;
|
if (index < 0 || index >= a->count) return 0;
|
||||||
if (out) *out = a->items[index]; /* transfer ownership */
|
if (out)
|
||||||
else free_value(a->items[index]);
|
*out = a->items[index]; /* transfer ownership */
|
||||||
|
else
|
||||||
|
free_value(a->items[index]);
|
||||||
/* shift left */
|
/* shift left */
|
||||||
for (int i = index; i < a->count - 1; ++i) {
|
for (int i = index; i < a->count - 1; ++i) {
|
||||||
a->items[i] = a->items[i + 1];
|
a->items[i] = a->items[i + 1];
|
||||||
|
|
@ -221,8 +233,10 @@ Value array_concat(const Value *av, const Value *bv) {
|
||||||
if (total <= 0) return make_array_from_values(NULL, 0);
|
if (total <= 0) return make_array_from_values(NULL, 0);
|
||||||
Value *tmp = (Value *)malloc(sizeof(Value) * total);
|
Value *tmp = (Value *)malloc(sizeof(Value) * total);
|
||||||
if (!tmp) return make_nil();
|
if (!tmp) return make_nil();
|
||||||
for (int i = 0; i < na; ++i) tmp[i] = a->items[i];
|
for (int i = 0; i < na; ++i)
|
||||||
for (int j = 0; j < nb; ++j) tmp[na + j] = b->items[j];
|
tmp[i] = a->items[i];
|
||||||
|
for (int j = 0; j < nb; ++j)
|
||||||
|
tmp[na + j] = b->items[j];
|
||||||
Value out = make_array_from_values(tmp, total);
|
Value out = make_array_from_values(tmp, total);
|
||||||
/* free temporaries we copied from (deep copy in make_array_from_values) */
|
/* free temporaries we copied from (deep copy in make_array_from_values) */
|
||||||
free(tmp);
|
free(tmp);
|
||||||
|
|
@ -465,13 +479,16 @@ int value_equals(const Value *a, const Value *b) {
|
||||||
}
|
}
|
||||||
if (a->type != b->type) return 0;
|
if (a->type != b->type) return 0;
|
||||||
switch (a->type) {
|
switch (a->type) {
|
||||||
case VAL_INT: return a->i == b->i;
|
case VAL_INT:
|
||||||
case VAL_BOOL: return (a->i != 0) == (b->i != 0);
|
return a->i == b->i;
|
||||||
|
case VAL_BOOL:
|
||||||
|
return (a->i != 0) == (b->i != 0);
|
||||||
case VAL_STRING: {
|
case VAL_STRING: {
|
||||||
const char *sa = a->s ? a->s : "";
|
const char *sa = a->s ? a->s : "";
|
||||||
const char *sb = b->s ? b->s : "";
|
const char *sb = b->s ? b->s : "";
|
||||||
return strcmp(sa, sb) == 0;
|
return strcmp(sa, sb) == 0;
|
||||||
}
|
}
|
||||||
default: return 0;
|
default:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
241
src/vm.c
241
src/vm.c
|
|
@ -18,21 +18,21 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#ifdef __unix__
|
#ifdef __unix__
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
/* For hidden input (password) handling in OP_INPUT_LINE */
|
/* For hidden input (password) handling in OP_INPUT_LINE */
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
|
@ -52,8 +52,8 @@
|
||||||
|
|
||||||
/* Shared Notcurses state (optional) */
|
/* Shared Notcurses state (optional) */
|
||||||
#ifdef FUN_WITH_NOTCURSES
|
#ifdef FUN_WITH_NOTCURSES
|
||||||
# include <wchar.h> /* ensure wcwidth/wcswidth prototypes present before notcurses.h on some systems */
|
|
||||||
#include <notcurses/notcurses.h>
|
#include <notcurses/notcurses.h>
|
||||||
|
#include <wchar.h> /* ensure wcwidth/wcswidth prototypes present before notcurses.h on some systems */
|
||||||
#endif
|
#endif
|
||||||
#include "vm/notcurses/common.h"
|
#include "vm/notcurses/common.h"
|
||||||
|
|
||||||
|
|
@ -67,14 +67,14 @@
|
||||||
/* Note: INI opcode handlers are included below; changes in vm/ini/ .c files
|
/* Note: INI opcode handlers are included below; changes in vm/ini/ .c files
|
||||||
* require vm.c to rebuild. */
|
* require vm.c to rebuild. */
|
||||||
#include "external/json.c"
|
#include "external/json.c"
|
||||||
|
#include "external/libressl.c"
|
||||||
#include "external/libsql.c"
|
#include "external/libsql.c"
|
||||||
#include "external/pcsc.c"
|
#include "external/openssl.c"
|
||||||
#include "external/pcre2.c"
|
#include "external/pcre2.c"
|
||||||
|
#include "external/pcsc.c"
|
||||||
#include "external/sqlite.c"
|
#include "external/sqlite.c"
|
||||||
#include "external/tcltk.c"
|
#include "external/tcltk.c"
|
||||||
#include "external/xml2.c"
|
#include "external/xml2.c"
|
||||||
#include "external/openssl.c"
|
|
||||||
#include "external/libressl.c"
|
|
||||||
|
|
||||||
/* forward declarations for include mapping used in error reporting */
|
/* forward declarations for include mapping used in error reporting */
|
||||||
extern char *preprocess_includes(const char *src);
|
extern char *preprocess_includes(const char *src);
|
||||||
|
|
@ -112,14 +112,18 @@ static int fun_vm_vfprintf(FILE *stream, const char *fmt, va_list ap) {
|
||||||
/* derive source line by scanning back to the most recent OP_LINE marker */
|
/* derive source line by scanning back to the most recent OP_LINE marker */
|
||||||
for (int i = ip; i >= 0; --i) {
|
for (int i = ip; i >= 0; --i) {
|
||||||
Instruction prev = f->fn->instructions[i];
|
Instruction prev = f->fn->instructions[i];
|
||||||
if (prev.op == OP_LINE) { line = prev.operand; break; }
|
if (prev.op == OP_LINE) {
|
||||||
|
line = prev.operand;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* fallback to VM's last recorded line if no marker found */
|
/* fallback to VM's last recorded line if no marker found */
|
||||||
if (line <= 0) line = g_active_vm->current_line > 0 ? g_active_vm->current_line : 1;
|
if (line <= 0) line = g_active_vm->current_line > 0 ? g_active_vm->current_line : 1;
|
||||||
|
|
||||||
/* If this function was compiled from an include-expanded source, map to the included file */
|
/* If this function was compiled from an include-expanded source, map to the included file */
|
||||||
if (sfile && line > 0) {
|
if (sfile && line > 0) {
|
||||||
char mapped_path[1024]; int mapped_line = line;
|
char mapped_path[1024];
|
||||||
|
int mapped_line = line;
|
||||||
if (map_expanded_line_to_include(sfile, line, mapped_path, sizeof(mapped_path), &mapped_line)) {
|
if (map_expanded_line_to_include(sfile, line, mapped_path, sizeof(mapped_path), &mapped_line)) {
|
||||||
sfile = strdup(mapped_path); /* leak on purpose for simplicity; this is rare */
|
sfile = strdup(mapped_path); /* leak on purpose for simplicity; this is rare */
|
||||||
line = mapped_line;
|
line = mapped_line;
|
||||||
|
|
@ -157,10 +161,16 @@ static int map_expanded_line_to_include(const char *path, int line, char *out_pa
|
||||||
if (!f) return 0;
|
if (!f) return 0;
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
long sz = ftell(f);
|
long sz = ftell(f);
|
||||||
if (sz < 0) { fclose(f); return 0; }
|
if (sz < 0) {
|
||||||
|
fclose(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
rewind(f);
|
rewind(f);
|
||||||
char *buf = (char *)malloc((size_t)sz + 1);
|
char *buf = (char *)malloc((size_t)sz + 1);
|
||||||
if (!buf) { fclose(f); return 0; }
|
if (!buf) {
|
||||||
|
fclose(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
size_t n = fread(buf, 1, (size_t)sz, f);
|
size_t n = fread(buf, 1, (size_t)sz, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
buf[n] = '\0';
|
buf[n] = '\0';
|
||||||
|
|
@ -171,12 +181,16 @@ static int map_expanded_line_to_include(const char *path, int line, char *out_pa
|
||||||
|
|
||||||
/* find start offset of requested 1-based line */
|
/* find start offset of requested 1-based line */
|
||||||
size_t len = strlen(prep);
|
size_t len = strlen(prep);
|
||||||
size_t pos = 0; int cur = 1;
|
size_t pos = 0;
|
||||||
|
int cur = 1;
|
||||||
while (pos < len && cur < line) {
|
while (pos < len && cur < line) {
|
||||||
if (prep[pos] == '\n') cur++;
|
if (prep[pos] == '\n') cur++;
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
if (cur != line) { free(prep); return 0; }
|
if (cur != line) {
|
||||||
|
free(prep);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* scan backward to find last include marker line */
|
/* scan backward to find last include marker line */
|
||||||
const char *marker = "// __include_begin__: ";
|
const char *marker = "// __include_begin__: ";
|
||||||
|
|
@ -185,13 +199,15 @@ static int map_expanded_line_to_include(const char *path, int line, char *out_pa
|
||||||
while (scan > 0) {
|
while (scan > 0) {
|
||||||
/* find start of this line */
|
/* find start of this line */
|
||||||
size_t ls = scan;
|
size_t ls = scan;
|
||||||
while (ls > 0 && prep[ls - 1] != '\n') ls--;
|
while (ls > 0 && prep[ls - 1] != '\n')
|
||||||
|
ls--;
|
||||||
/* check marker */
|
/* check marker */
|
||||||
if (ls + mlen <= len && strncmp(prep + ls, marker, mlen) == 0) {
|
if (ls + mlen <= len && strncmp(prep + ls, marker, mlen) == 0) {
|
||||||
/* extract included path up to EOL or ' as ' */
|
/* extract included path up to EOL or ' as ' */
|
||||||
size_t p = ls + mlen;
|
size_t p = ls + mlen;
|
||||||
size_t pe = p;
|
size_t pe = p;
|
||||||
while (pe < len && prep[pe] != '\n' && !(prep[pe] == ' ' && pe + 3 < len && strncmp(prep + pe, " as ", 4) == 0)) pe++;
|
while (pe < len && prep[pe] != '\n' && !(prep[pe] == ' ' && pe + 3 < len && strncmp(prep + pe, " as ", 4) == 0))
|
||||||
|
pe++;
|
||||||
size_t copy = (pe - p) < (out_path_cap - 1) ? (pe - p) : (out_path_cap - 1);
|
size_t copy = (pe - p) < (out_path_cap - 1) ? (pe - p) : (out_path_cap - 1);
|
||||||
memcpy(out_path, prep + p, copy);
|
memcpy(out_path, prep + p, copy);
|
||||||
out_path[copy] = '\0';
|
out_path[copy] = '\0';
|
||||||
|
|
@ -199,9 +215,13 @@ static int map_expanded_line_to_include(const char *path, int line, char *out_pa
|
||||||
int inner = 1;
|
int inner = 1;
|
||||||
size_t q = pe;
|
size_t q = pe;
|
||||||
/* skip to next line start */
|
/* skip to next line start */
|
||||||
while (q < len && prep[q] != '\n') q++;
|
while (q < len && prep[q] != '\n')
|
||||||
|
q++;
|
||||||
if (q < len && prep[q] == '\n') q++;
|
if (q < len && prep[q] == '\n') q++;
|
||||||
while (q < pos) { if (prep[q] == '\n') inner++; q++; }
|
while (q < pos) {
|
||||||
|
if (prep[q] == '\n') inner++;
|
||||||
|
q++;
|
||||||
|
}
|
||||||
*out_line = inner;
|
*out_line = inner;
|
||||||
free(prep);
|
free(prep);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -310,15 +330,24 @@ Dev tips:
|
||||||
|
|
||||||
static const char *value_type_name(ValueType t) {
|
static const char *value_type_name(ValueType t) {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case VAL_FUNCTION: return "function";
|
case VAL_FUNCTION:
|
||||||
case VAL_INT: return "int";
|
return "function";
|
||||||
case VAL_FLOAT: return "float";
|
case VAL_INT:
|
||||||
case VAL_BOOL: return "boolean";
|
return "int";
|
||||||
case VAL_ARRAY: return "array";
|
case VAL_FLOAT:
|
||||||
case VAL_MAP: return "map";
|
return "float";
|
||||||
case VAL_NIL: return "nil";
|
case VAL_BOOL:
|
||||||
case VAL_STRING: return "string";
|
return "boolean";
|
||||||
default: return "unknown";
|
case VAL_ARRAY:
|
||||||
|
return "array";
|
||||||
|
case VAL_MAP:
|
||||||
|
return "map";
|
||||||
|
case VAL_NIL:
|
||||||
|
return "nil";
|
||||||
|
case VAL_STRING:
|
||||||
|
return "string";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -328,7 +357,8 @@ void vm_clear_output(VM *vm) {
|
||||||
}
|
}
|
||||||
vm->output_count = 0;
|
vm->output_count = 0;
|
||||||
// reset partial flags
|
// reset partial flags
|
||||||
for (int i = 0; i < OUTPUT_SIZE; ++i) vm->output_is_partial[i] = 0;
|
for (int i = 0; i < OUTPUT_SIZE; ++i)
|
||||||
|
vm->output_is_partial[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm_free(VM *vm) {
|
void vm_free(VM *vm) {
|
||||||
|
|
@ -523,7 +553,8 @@ size_t vm_offset_of_globals(void) {
|
||||||
static void frame_init(Frame *f) {
|
static void frame_init(Frame *f) {
|
||||||
f->fn = NULL;
|
f->fn = NULL;
|
||||||
f->ip = 0;
|
f->ip = 0;
|
||||||
for (int i = 0; i < MAX_FRAME_LOCALS; ++i) f->locals[i] = make_nil();
|
for (int i = 0; i < MAX_FRAME_LOCALS; ++i)
|
||||||
|
f->locals[i] = make_nil();
|
||||||
f->try_sp = -1;
|
f->try_sp = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -531,7 +562,8 @@ void vm_init(VM *vm) {
|
||||||
vm->sp = -1;
|
vm->sp = -1;
|
||||||
vm->fp = -1;
|
vm->fp = -1;
|
||||||
vm->output_count = 0;
|
vm->output_count = 0;
|
||||||
for (int i = 0; i < OUTPUT_SIZE; ++i) vm->output_is_partial[i] = 0;
|
for (int i = 0; i < OUTPUT_SIZE; ++i)
|
||||||
|
vm->output_is_partial[i] = 0;
|
||||||
vm->instr_count = 0;
|
vm->instr_count = 0;
|
||||||
vm->exit_code = 0;
|
vm->exit_code = 0;
|
||||||
vm->trace_enabled = 0;
|
vm->trace_enabled = 0;
|
||||||
|
|
@ -657,12 +689,14 @@ void vm_run(VM *vm, Bytecode *entry) {
|
||||||
|
|
||||||
if (vm->trace_enabled) {
|
if (vm->trace_enabled) {
|
||||||
const char *opname = (inst.op >= 0 && inst.op < (int)(sizeof(opcode_names) / sizeof(opcode_names[0])))
|
const char *opname = (inst.op >= 0 && inst.op < (int)(sizeof(opcode_names) / sizeof(opcode_names[0])))
|
||||||
? opcode_names[inst.op] : "???";
|
? opcode_names[inst.op]
|
||||||
|
: "???";
|
||||||
const char *fname = f->fn && f->fn->name ? f->fn->name : "<entry>";
|
const char *fname = f->fn && f->fn->name ? f->fn->name : "<entry>";
|
||||||
const char *sfile = f->fn && f->fn->source_file ? f->fn->source_file : "<unknown>";
|
const char *sfile = f->fn && f->fn->source_file ? f->fn->source_file : "<unknown>";
|
||||||
/* Dump up to top 4 stack values */
|
/* Dump up to top 4 stack values */
|
||||||
int count = vm->sp + 1;
|
int count = vm->sp + 1;
|
||||||
int start = count - 4; if (start < 0) start = 0;
|
int start = count - 4;
|
||||||
|
if (start < 0) start = 0;
|
||||||
fprintf(stdout, "TRACE %s:%d %s ip=%d %-14s %d | stack[%d]=[", sfile, vm->current_line, fname, f->ip - 1, opname, inst.operand, count);
|
fprintf(stdout, "TRACE %s:%d %s ip=%d %-14s %d | stack[%d]=[", sfile, vm->current_line, fname, f->ip - 1, opname, inst.operand, count);
|
||||||
for (int i = start; i < count; ++i) {
|
for (int i = start; i < count; ++i) {
|
||||||
char *sv = value_to_string_alloc(&vm->stack[i]);
|
char *sv = value_to_string_alloc(&vm->stack[i]);
|
||||||
|
|
@ -716,13 +750,13 @@ void vm_run(VM *vm, Bytecode *entry) {
|
||||||
|
|
||||||
/* Bitwise and shifts/rotates */
|
/* Bitwise and shifts/rotates */
|
||||||
#include "vm/bitwise/band.c"
|
#include "vm/bitwise/band.c"
|
||||||
|
#include "vm/bitwise/bnot.c"
|
||||||
#include "vm/bitwise/bor.c"
|
#include "vm/bitwise/bor.c"
|
||||||
#include "vm/bitwise/bxor.c"
|
#include "vm/bitwise/bxor.c"
|
||||||
#include "vm/bitwise/bnot.c"
|
|
||||||
#include "vm/bitwise/shl.c"
|
|
||||||
#include "vm/bitwise/shr.c"
|
|
||||||
#include "vm/bitwise/rol.c"
|
#include "vm/bitwise/rol.c"
|
||||||
#include "vm/bitwise/ror.c"
|
#include "vm/bitwise/ror.c"
|
||||||
|
#include "vm/bitwise/shl.c"
|
||||||
|
#include "vm/bitwise/shr.c"
|
||||||
|
|
||||||
#include "vm/core/call.c"
|
#include "vm/core/call.c"
|
||||||
#include "vm/core/dup.c"
|
#include "vm/core/dup.c"
|
||||||
|
|
@ -743,9 +777,9 @@ void vm_run(VM *vm, Bytecode *entry) {
|
||||||
#include "vm/core/try_pop.c"
|
#include "vm/core/try_pop.c"
|
||||||
#include "vm/core/try_push.c"
|
#include "vm/core/try_push.c"
|
||||||
|
|
||||||
|
#include "vm/io/input_line.c"
|
||||||
#include "vm/io/read_file.c"
|
#include "vm/io/read_file.c"
|
||||||
#include "vm/io/write_file.c"
|
#include "vm/io/write_file.c"
|
||||||
#include "vm/io/input_line.c"
|
|
||||||
|
|
||||||
#include "vm/logic/and.c"
|
#include "vm/logic/and.c"
|
||||||
#include "vm/logic/eq.c"
|
#include "vm/logic/eq.c"
|
||||||
|
|
@ -763,155 +797,155 @@ void vm_run(VM *vm, Bytecode *entry) {
|
||||||
#include "vm/maps/values.c"
|
#include "vm/maps/values.c"
|
||||||
|
|
||||||
#include "vm/math/abs.c"
|
#include "vm/math/abs.c"
|
||||||
|
#include "vm/math/ceil.c"
|
||||||
#include "vm/math/clamp.c"
|
#include "vm/math/clamp.c"
|
||||||
#include "vm/math/max.c"
|
#include "vm/math/cos.c"
|
||||||
#include "vm/math/min.c"
|
#include "vm/math/exp.c"
|
||||||
|
#include "vm/math/floor.c"
|
||||||
#include "vm/math/fmax.c"
|
#include "vm/math/fmax.c"
|
||||||
#include "vm/math/fmin.c"
|
#include "vm/math/fmin.c"
|
||||||
#include "vm/math/mod.c"
|
#include "vm/math/gcd.c"
|
||||||
#include "vm/math/pow.c"
|
#include "vm/math/isqrt.c"
|
||||||
#include "vm/math/floor.c"
|
#include "vm/math/lcm.c"
|
||||||
#include "vm/math/ceil.c"
|
|
||||||
#include "vm/math/trunc.c"
|
|
||||||
#include "vm/math/round.c"
|
|
||||||
#include "vm/math/sin.c"
|
|
||||||
#include "vm/math/cos.c"
|
|
||||||
#include "vm/math/tan.c"
|
|
||||||
#include "vm/math/exp.c"
|
|
||||||
#include "vm/math/log.c"
|
#include "vm/math/log.c"
|
||||||
#include "vm/math/log10.c"
|
#include "vm/math/log10.c"
|
||||||
#include "vm/math/sqrt.c"
|
#include "vm/math/max.c"
|
||||||
|
#include "vm/math/min.c"
|
||||||
|
#include "vm/math/mod.c"
|
||||||
|
#include "vm/math/pow.c"
|
||||||
#include "vm/math/random_int.c"
|
#include "vm/math/random_int.c"
|
||||||
#include "vm/math/random_seed.c"
|
#include "vm/math/random_seed.c"
|
||||||
#include "vm/math/gcd.c"
|
#include "vm/math/round.c"
|
||||||
#include "vm/math/lcm.c"
|
|
||||||
#include "vm/math/isqrt.c"
|
|
||||||
#include "vm/math/sign.c"
|
#include "vm/math/sign.c"
|
||||||
|
#include "vm/math/sin.c"
|
||||||
|
#include "vm/math/sqrt.c"
|
||||||
|
#include "vm/math/tan.c"
|
||||||
|
#include "vm/math/trunc.c"
|
||||||
|
|
||||||
/* Rust FFI demo opcode(s) */
|
/* Rust FFI demo opcode(s) */
|
||||||
|
#include "vm/rust/get_sp.c"
|
||||||
#include "vm/rust/hello.c"
|
#include "vm/rust/hello.c"
|
||||||
#include "vm/rust/hello_args.c"
|
#include "vm/rust/hello_args.c"
|
||||||
#include "vm/rust/hello_args_return.c"
|
#include "vm/rust/hello_args_return.c"
|
||||||
#include "vm/rust/get_sp.c"
|
|
||||||
#include "vm/rust/set_exit.c"
|
#include "vm/rust/set_exit.c"
|
||||||
|
|
||||||
|
#include "vm/os/clock_mono_ms.c"
|
||||||
|
#include "vm/os/date_format.c"
|
||||||
#include "vm/os/env.c"
|
#include "vm/os/env.c"
|
||||||
#include "vm/os/env_all.c"
|
#include "vm/os/env_all.c"
|
||||||
#include "vm/os/fun_version.c"
|
#include "vm/os/fun_version.c"
|
||||||
|
#include "vm/os/proc_run.c"
|
||||||
|
#include "vm/os/proc_system.c"
|
||||||
|
#include "vm/os/random_number.c"
|
||||||
|
#include "vm/os/serial_close.c"
|
||||||
|
#include "vm/os/serial_config.c"
|
||||||
|
#include "vm/os/serial_open.c"
|
||||||
|
#include "vm/os/serial_recv.c"
|
||||||
|
#include "vm/os/serial_send.c"
|
||||||
#include "vm/os/sleep_ms.c"
|
#include "vm/os/sleep_ms.c"
|
||||||
#include "vm/os/thread_join.c"
|
#include "vm/os/thread_join.c"
|
||||||
#include "vm/os/thread_spawn.c"
|
#include "vm/os/thread_spawn.c"
|
||||||
#include "vm/os/proc_run.c"
|
|
||||||
#include "vm/os/proc_system.c"
|
|
||||||
#include "vm/os/time_now_ms.c"
|
#include "vm/os/time_now_ms.c"
|
||||||
#include "vm/os/clock_mono_ms.c"
|
|
||||||
#include "vm/os/date_format.c"
|
|
||||||
#include "vm/os/random_number.c"
|
|
||||||
#include "vm/os/serial_open.c"
|
|
||||||
#include "vm/os/serial_config.c"
|
|
||||||
#include "vm/os/serial_send.c"
|
|
||||||
#include "vm/os/serial_recv.c"
|
|
||||||
#include "vm/os/serial_close.c"
|
|
||||||
|
|
||||||
/* Socket ops */
|
/* Socket ops */
|
||||||
#include "vm/os/socket_tcp_listen.c"
|
#include "vm/os/socket_close.c"
|
||||||
|
#include "vm/os/socket_recv.c"
|
||||||
|
#include "vm/os/socket_send.c"
|
||||||
#include "vm/os/socket_tcp_accept.c"
|
#include "vm/os/socket_tcp_accept.c"
|
||||||
#include "vm/os/socket_tcp_connect.c"
|
#include "vm/os/socket_tcp_connect.c"
|
||||||
#include "vm/os/socket_send.c"
|
#include "vm/os/socket_tcp_listen.c"
|
||||||
#include "vm/os/socket_recv.c"
|
|
||||||
#include "vm/os/socket_close.c"
|
|
||||||
#include "vm/os/socket_unix_listen.c"
|
|
||||||
#include "vm/os/socket_unix_connect.c"
|
#include "vm/os/socket_unix_connect.c"
|
||||||
|
#include "vm/os/socket_unix_listen.c"
|
||||||
|
|
||||||
#ifdef FUN_WITH_PCSC
|
#ifdef FUN_WITH_PCSC
|
||||||
#include "vm/pcsc/establish.c"
|
|
||||||
#include "vm/pcsc/release.c"
|
|
||||||
#include "vm/pcsc/list_readers.c"
|
|
||||||
#include "vm/pcsc/connect.c"
|
#include "vm/pcsc/connect.c"
|
||||||
#include "vm/pcsc/disconnect.c"
|
#include "vm/pcsc/disconnect.c"
|
||||||
|
#include "vm/pcsc/establish.c"
|
||||||
|
#include "vm/pcsc/list_readers.c"
|
||||||
|
#include "vm/pcsc/release.c"
|
||||||
#include "vm/pcsc/transmit.c"
|
#include "vm/pcsc/transmit.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* JSON ops (implemented in jsonc.c, included above) */
|
/* JSON ops (implemented in jsonc.c, included above) */
|
||||||
#ifdef FUN_WITH_JSON
|
#ifdef FUN_WITH_JSON
|
||||||
|
#include "vm/json/from_file.c"
|
||||||
#include "vm/json/parse.c"
|
#include "vm/json/parse.c"
|
||||||
#include "vm/json/stringify.c"
|
#include "vm/json/stringify.c"
|
||||||
#include "vm/json/from_file.c"
|
|
||||||
#include "vm/json/to_file.c"
|
#include "vm/json/to_file.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* XML ops (libxml2) */
|
/* XML ops (libxml2) */
|
||||||
#ifdef FUN_WITH_XML2
|
#ifdef FUN_WITH_XML2
|
||||||
|
#include "vm/xml/name.c"
|
||||||
#include "vm/xml/parse.c"
|
#include "vm/xml/parse.c"
|
||||||
#include "vm/xml/root.c"
|
#include "vm/xml/root.c"
|
||||||
#include "vm/xml/name.c"
|
|
||||||
#include "vm/xml/text.c"
|
#include "vm/xml/text.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* INI ops (iniparser 4.2.6) */
|
/* INI ops (iniparser 4.2.6) */
|
||||||
#ifdef FUN_WITH_INI
|
#ifdef FUN_WITH_INI
|
||||||
#include "vm/ini/load.c"
|
|
||||||
#include "vm/ini/free.c"
|
#include "vm/ini/free.c"
|
||||||
#include "vm/ini/get_string.c"
|
|
||||||
#include "vm/ini/get_int.c"
|
|
||||||
#include "vm/ini/get_double.c"
|
|
||||||
#include "vm/ini/get_bool.c"
|
#include "vm/ini/get_bool.c"
|
||||||
|
#include "vm/ini/get_double.c"
|
||||||
|
#include "vm/ini/get_int.c"
|
||||||
|
#include "vm/ini/get_string.c"
|
||||||
|
#include "vm/ini/load.c"
|
||||||
|
#include "vm/ini/save.c"
|
||||||
#include "vm/ini/set.c"
|
#include "vm/ini/set.c"
|
||||||
#include "vm/ini/unset.c"
|
#include "vm/ini/unset.c"
|
||||||
#include "vm/ini/save.c"
|
|
||||||
#else
|
#else
|
||||||
#include "vm/ini/stubs.c"
|
#include "vm/ini/stubs.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* CURL ops */
|
/* CURL ops */
|
||||||
#ifdef FUN_WITH_CURL
|
#ifdef FUN_WITH_CURL
|
||||||
|
#include "vm/curl/download.c"
|
||||||
#include "vm/curl/get.c"
|
#include "vm/curl/get.c"
|
||||||
#include "vm/curl/post.c"
|
#include "vm/curl/post.c"
|
||||||
#include "vm/curl/download.c"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* OpenSSL ops (md5/sha256/sha512/ripemd160) */
|
/* OpenSSL ops (md5/sha256/sha512/ripemd160) */
|
||||||
#ifdef FUN_WITH_OPENSSL
|
#ifdef FUN_WITH_OPENSSL
|
||||||
#include "vm/openssl/md5.c"
|
#include "vm/openssl/md5.c"
|
||||||
|
#include "vm/openssl/ripemd160.c"
|
||||||
#include "vm/openssl/sha256.c"
|
#include "vm/openssl/sha256.c"
|
||||||
#include "vm/openssl/sha512.c"
|
#include "vm/openssl/sha512.c"
|
||||||
#include "vm/openssl/ripemd160.c"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* LibreSSL ops (md5/sha256/sha512/ripemd160) */
|
/* LibreSSL ops (md5/sha256/sha512/ripemd160) */
|
||||||
#ifdef FUN_WITH_LIBRESSL
|
#ifdef FUN_WITH_LIBRESSL
|
||||||
#include "vm/libressl/md5.c"
|
#include "vm/libressl/md5.c"
|
||||||
|
#include "vm/libressl/ripemd160.c"
|
||||||
#include "vm/libressl/sha256.c"
|
#include "vm/libressl/sha256.c"
|
||||||
#include "vm/libressl/sha512.c"
|
#include "vm/libressl/sha512.c"
|
||||||
#include "vm/libressl/ripemd160.c"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Tk (Tcl/Tk) ops */
|
/* Tk (Tcl/Tk) ops */
|
||||||
#ifdef FUN_WITH_TCLTK
|
#ifdef FUN_WITH_TCLTK
|
||||||
#include "vm/tk/eval.c"
|
|
||||||
#include "vm/tk/result.c"
|
|
||||||
#include "vm/tk/loop.c"
|
|
||||||
#include "vm/tk/wm_title.c"
|
|
||||||
#include "vm/tk/label.c"
|
|
||||||
#include "vm/tk/button.c"
|
|
||||||
#include "vm/tk/pack.c"
|
|
||||||
#include "vm/tk/bind.c"
|
#include "vm/tk/bind.c"
|
||||||
|
#include "vm/tk/button.c"
|
||||||
|
#include "vm/tk/eval.c"
|
||||||
|
#include "vm/tk/label.c"
|
||||||
|
#include "vm/tk/loop.c"
|
||||||
|
#include "vm/tk/pack.c"
|
||||||
|
#include "vm/tk/result.c"
|
||||||
|
#include "vm/tk/wm_title.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Notcurses TUI ops (optional) */
|
/* Notcurses TUI ops (optional) */
|
||||||
#ifdef FUN_WITH_NOTCURSES
|
#ifdef FUN_WITH_NOTCURSES
|
||||||
#include "vm/notcurses/init.c"
|
|
||||||
#include "vm/notcurses/shutdown.c"
|
|
||||||
#include "vm/notcurses/clear.c"
|
#include "vm/notcurses/clear.c"
|
||||||
#include "vm/notcurses/draw_text.c"
|
#include "vm/notcurses/draw_text.c"
|
||||||
#include "vm/notcurses/getch.c"
|
#include "vm/notcurses/getch.c"
|
||||||
|
#include "vm/notcurses/init.c"
|
||||||
|
#include "vm/notcurses/shutdown.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* SQLite ops */
|
/* SQLite ops */
|
||||||
#ifdef FUN_WITH_SQLITE
|
#ifdef FUN_WITH_SQLITE
|
||||||
#include "vm/sqlite/open.c"
|
|
||||||
#include "vm/sqlite/close.c"
|
#include "vm/sqlite/close.c"
|
||||||
#include "vm/sqlite/exec.c"
|
#include "vm/sqlite/exec.c"
|
||||||
|
#include "vm/sqlite/open.c"
|
||||||
#include "vm/sqlite/query.c"
|
#include "vm/sqlite/query.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -933,44 +967,45 @@ void vm_run(VM *vm, Bytecode *entry) {
|
||||||
|
|
||||||
/* libsql ops (independent) */
|
/* libsql ops (independent) */
|
||||||
#ifdef FUN_WITH_LIBSQL
|
#ifdef FUN_WITH_LIBSQL
|
||||||
#include "vm/libsql/open.c"
|
|
||||||
#include "vm/libsql/close.c"
|
#include "vm/libsql/close.c"
|
||||||
#include "vm/libsql/exec.c"
|
#include "vm/libsql/exec.c"
|
||||||
|
#include "vm/libsql/open.c"
|
||||||
#include "vm/libsql/query.c"
|
#include "vm/libsql/query.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* PCRE2 ops */
|
/* PCRE2 ops */
|
||||||
#ifdef FUN_WITH_PCRE2
|
#ifdef FUN_WITH_PCRE2
|
||||||
#include "vm/pcre2/test.c"
|
|
||||||
#include "vm/pcre2/match.c"
|
|
||||||
#include "vm/pcre2/findall.c"
|
#include "vm/pcre2/findall.c"
|
||||||
|
#include "vm/pcre2/match.c"
|
||||||
|
#include "vm/pcre2/test.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "vm/strings/find.c"
|
#include "vm/strings/find.c"
|
||||||
#include "vm/strings/regex_match.c"
|
#include "vm/strings/regex_match.c"
|
||||||
#include "vm/strings/regex_search.c"
|
|
||||||
#include "vm/strings/regex_replace.c"
|
#include "vm/strings/regex_replace.c"
|
||||||
|
#include "vm/strings/regex_search.c"
|
||||||
#include "vm/strings/split.c"
|
#include "vm/strings/split.c"
|
||||||
#include "vm/strings/substr.c"
|
#include "vm/strings/substr.c"
|
||||||
|
|
||||||
|
#include "vm/cast.c"
|
||||||
|
#include "vm/echo.c"
|
||||||
#include "vm/len.c"
|
#include "vm/len.c"
|
||||||
#include "vm/line.c"
|
#include "vm/line.c"
|
||||||
|
#include "vm/os/list_dir.c"
|
||||||
#include "vm/print.c"
|
#include "vm/print.c"
|
||||||
#include "vm/echo.c"
|
#include "vm/sclamp.c"
|
||||||
#include "vm/to_number.c"
|
#include "vm/to_number.c"
|
||||||
#include "vm/to_string.c"
|
#include "vm/to_string.c"
|
||||||
#include "vm/cast.c"
|
|
||||||
#include "vm/typeof.c"
|
#include "vm/typeof.c"
|
||||||
#include "vm/uclamp.c"
|
#include "vm/uclamp.c"
|
||||||
#include "vm/sclamp.c"
|
|
||||||
#include "vm/os/list_dir.c"
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (!opcode_is_valid(inst.op)) {
|
if (!opcode_is_valid(inst.op)) {
|
||||||
fprintf(stderr, "Runtime error: unknown opcode %d (%s) at instruction %d\n",
|
fprintf(stderr, "Runtime error: unknown opcode %d (%s) at instruction %d\n",
|
||||||
inst.op,
|
inst.op,
|
||||||
(inst.op >= 0 && inst.op < sizeof(opcode_names) / sizeof(opcode_names[0]))
|
(inst.op >= 0 && inst.op < sizeof(opcode_names) / sizeof(opcode_names[0]))
|
||||||
? opcode_names[inst.op] : "???",
|
? opcode_names[inst.op]
|
||||||
|
: "???",
|
||||||
f->ip - 1);
|
f->ip - 1);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
src/vm.h
3
src/vm.h
|
|
@ -61,8 +61,7 @@ static const char *opcode_names[] = {
|
||||||
/* C++ demo */
|
/* C++ demo */
|
||||||
"CPP_ADD",
|
"CPP_ADD",
|
||||||
/* Notcurses TUI (optional) */
|
/* Notcurses TUI (optional) */
|
||||||
"NC_INIT","NC_SHUTDOWN","NC_CLEAR","NC_DRAW_TEXT","NC_GETCH"
|
"NC_INIT", "NC_SHUTDOWN", "NC_CLEAR", "NC_DRAW_TEXT", "NC_GETCH"};
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Bytecode *fn;
|
Bytecode *fn;
|
||||||
|
|
|
||||||
|
|
@ -41,16 +41,23 @@ case OP_INDEX_GET: {
|
||||||
container.type, idx.type);
|
container.type, idx.type);
|
||||||
#endif
|
#endif
|
||||||
if (container.type == VAL_ARRAY) {
|
if (container.type == VAL_ARRAY) {
|
||||||
if (idx.type != VAL_INT) { fprintf(stderr, "INDEX_GET index must be int for array\n"); exit(1); }
|
if (idx.type != VAL_INT) {
|
||||||
|
fprintf(stderr, "INDEX_GET index must be int for array\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
Value elem;
|
Value elem;
|
||||||
if (!array_get_copy(&container, (int)idx.i, &elem)) {
|
if (!array_get_copy(&container, (int)idx.i, &elem)) {
|
||||||
fprintf(stderr, "Runtime error: index out of range\n"); exit(1);
|
fprintf(stderr, "Runtime error: index out of range\n");
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
free_value(container);
|
free_value(container);
|
||||||
free_value(idx);
|
free_value(idx);
|
||||||
push_value(vm, elem);
|
push_value(vm, elem);
|
||||||
} else if (container.type == VAL_MAP) {
|
} else if (container.type == VAL_MAP) {
|
||||||
if (idx.type != VAL_STRING) { fprintf(stderr, "INDEX_GET key must be string for map\n"); exit(1); }
|
if (idx.type != VAL_STRING) {
|
||||||
|
fprintf(stderr, "INDEX_GET key must be string for map\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
Value out;
|
Value out;
|
||||||
if (!map_get_copy(&container, idx.s ? idx.s : "", &out)) {
|
if (!map_get_copy(&container, idx.s ? idx.s : "", &out)) {
|
||||||
out = make_nil();
|
out = make_nil();
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@
|
||||||
* @date 2025-10-16
|
* @date 2025-10-16
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
case OP_INDEX_SET: {
|
case OP_INDEX_SET: {
|
||||||
Value v = pop_value(vm);
|
Value v = pop_value(vm);
|
||||||
Value idx = pop_value(vm);
|
Value idx = pop_value(vm);
|
||||||
|
|
@ -42,16 +41,24 @@ case OP_INDEX_SET: {
|
||||||
container.type, idx.type, v.type);
|
container.type, idx.type, v.type);
|
||||||
#endif
|
#endif
|
||||||
if (container.type == VAL_ARRAY) {
|
if (container.type == VAL_ARRAY) {
|
||||||
if (idx.type != VAL_INT) { fprintf(stderr, "INDEX_SET index must be int for array\n"); exit(1); }
|
if (idx.type != VAL_INT) {
|
||||||
|
fprintf(stderr, "INDEX_SET index must be int for array\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
if (!array_set(&container, (int)idx.i, v)) {
|
if (!array_set(&container, (int)idx.i, v)) {
|
||||||
fprintf(stderr, "Runtime error: index out of range\n"); exit(1);
|
fprintf(stderr, "Runtime error: index out of range\n");
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
free_value(container);
|
free_value(container);
|
||||||
free_value(idx);
|
free_value(idx);
|
||||||
} else if (container.type == VAL_MAP) {
|
} else if (container.type == VAL_MAP) {
|
||||||
if (idx.type != VAL_STRING) { fprintf(stderr, "INDEX_SET key must be string for map\n"); exit(1); }
|
if (idx.type != VAL_STRING) {
|
||||||
|
fprintf(stderr, "INDEX_SET key must be string for map\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
if (!map_set(&container, idx.s ? idx.s : "", v)) {
|
if (!map_set(&container, idx.s ? idx.s : "", v)) {
|
||||||
fprintf(stderr, "Runtime error: map set failed\n"); exit(1);
|
fprintf(stderr, "Runtime error: map set failed\n");
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
free_value(container);
|
free_value(container);
|
||||||
free_value(idx);
|
free_value(idx);
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,10 @@ case OP_MAKE_ARRAY: {
|
||||||
}
|
}
|
||||||
/* pop n values into temp array preserving original order */
|
/* pop n values into temp array preserving original order */
|
||||||
Value *vals = (Value *)malloc(sizeof(Value) * n);
|
Value *vals = (Value *)malloc(sizeof(Value) * n);
|
||||||
if (!vals) { fprintf(stderr, "Runtime error: OOM in MAKE_ARRAY\n"); exit(1); }
|
if (!vals) {
|
||||||
|
fprintf(stderr, "Runtime error: OOM in MAKE_ARRAY\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
for (int i = n - 1; i >= 0; --i) {
|
for (int i = n - 1; i >= 0; --i) {
|
||||||
vals[i] = pop_value(vm); /* take ownership */
|
vals[i] = pop_value(vm); /* take ownership */
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,12 +45,16 @@ case OP_CAST: {
|
||||||
} else if (v.type == VAL_STRING) {
|
} else if (v.type == VAL_STRING) {
|
||||||
const char *s = v.s ? v.s : "";
|
const char *s = v.s ? v.s : "";
|
||||||
const char *p = s;
|
const char *p = s;
|
||||||
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') p++;
|
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
|
||||||
|
p++;
|
||||||
char *endp = NULL;
|
char *endp = NULL;
|
||||||
long long parsed = strtoll(p, &endp, 10);
|
long long parsed = strtoll(p, &endp, 10);
|
||||||
while (endp && (*endp == ' ' || *endp == '\t' || *endp == '\r' || *endp == '\n')) endp++;
|
while (endp && (*endp == ' ' || *endp == '\t' || *endp == '\r' || *endp == '\n'))
|
||||||
if (endp && *endp != '\0') out = make_int(0);
|
endp++;
|
||||||
else out = make_int((int64_t)parsed);
|
if (endp && *endp != '\0')
|
||||||
|
out = make_int(0);
|
||||||
|
else
|
||||||
|
out = make_int((int64_t)parsed);
|
||||||
} else {
|
} else {
|
||||||
out = make_int(0);
|
out = make_int(0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,10 @@
|
||||||
|
|
||||||
case OP_RETURN: {
|
case OP_RETURN: {
|
||||||
Value retv;
|
Value retv;
|
||||||
if (vm->sp >= 0) retv = pop_value(vm);
|
if (vm->sp >= 0)
|
||||||
else retv = make_nil();
|
retv = pop_value(vm);
|
||||||
|
else
|
||||||
|
retv = make_nil();
|
||||||
vm_pop_frame(vm);
|
vm_pop_frame(vm);
|
||||||
push_value(vm, retv);
|
push_value(vm, retv);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,16 @@ case OP_CURL_DOWNLOAD: {
|
||||||
}
|
}
|
||||||
FILE *fp = fopen(path, "wb");
|
FILE *fp = fopen(path, "wb");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
free(url); free(path);
|
free(url);
|
||||||
|
free(path);
|
||||||
push_value(vm, make_int(0));
|
push_value(vm, make_int(0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
CURL *h = curl_easy_init();
|
CURL *h = curl_easy_init();
|
||||||
if (!h) {
|
if (!h) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
free(url); free(path);
|
free(url);
|
||||||
|
free(path);
|
||||||
push_value(vm, make_int(0));
|
push_value(vm, make_int(0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -35,12 +37,18 @@ case OP_CURL_DOWNLOAD: {
|
||||||
CURLcode rc = curl_easy_perform(h);
|
CURLcode rc = curl_easy_perform(h);
|
||||||
curl_easy_cleanup(h);
|
curl_easy_cleanup(h);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
free(url); free(path);
|
free(url);
|
||||||
if (rc != CURLE_OK) { push_value(vm, make_int(0)); break; }
|
free(path);
|
||||||
|
if (rc != CURLE_OK) {
|
||||||
|
push_value(vm, make_int(0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
push_value(vm, make_int(1));
|
push_value(vm, make_int(1));
|
||||||
#else
|
#else
|
||||||
Value a = pop_value(vm); free_value(a);
|
Value a = pop_value(vm);
|
||||||
Value b = pop_value(vm); free_value(b);
|
free_value(a);
|
||||||
|
Value b = pop_value(vm);
|
||||||
|
free_value(b);
|
||||||
push_value(vm, make_int(0));
|
push_value(vm, make_int(0));
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,17 @@ case OP_CURL_GET: {
|
||||||
Value vurl = pop_value(vm);
|
Value vurl = pop_value(vm);
|
||||||
char *url = value_to_string_alloc(&vurl);
|
char *url = value_to_string_alloc(&vurl);
|
||||||
free_value(vurl);
|
free_value(vurl);
|
||||||
if (!url) { push_value(vm, make_string("")); break; }
|
if (!url) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
FunCurlBuf buf = {NULL, 0};
|
FunCurlBuf buf = {NULL, 0};
|
||||||
CURL *h = curl_easy_init();
|
CURL *h = curl_easy_init();
|
||||||
if (!h) { free(url); push_value(vm, make_string("")); break; }
|
if (!h) {
|
||||||
|
free(url);
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
curl_easy_setopt(h, CURLOPT_URL, url);
|
curl_easy_setopt(h, CURLOPT_URL, url);
|
||||||
curl_easy_setopt(h, CURLOPT_FOLLOWLOCATION, 1L);
|
curl_easy_setopt(h, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
curl_easy_setopt(h, CURLOPT_WRITEFUNCTION, fun_curl_write_cb);
|
curl_easy_setopt(h, CURLOPT_WRITEFUNCTION, fun_curl_write_cb);
|
||||||
|
|
@ -26,7 +33,8 @@ case OP_CURL_GET: {
|
||||||
if (buf.d) free(buf.d);
|
if (buf.d) free(buf.d);
|
||||||
push_value(vm, s);
|
push_value(vm, s);
|
||||||
#else
|
#else
|
||||||
Value v = pop_value(vm); free_value(v);
|
Value v = pop_value(vm);
|
||||||
|
free_value(v);
|
||||||
push_value(vm, make_string(""));
|
push_value(vm, make_string(""));
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,20 @@ case OP_CURL_POST: {
|
||||||
char *body = value_to_string_alloc(&vbody);
|
char *body = value_to_string_alloc(&vbody);
|
||||||
free_value(vurl);
|
free_value(vurl);
|
||||||
free_value(vbody);
|
free_value(vbody);
|
||||||
if (!url) { if (body) free(body); push_value(vm, make_string("")); break; }
|
if (!url) {
|
||||||
|
if (body) free(body);
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (!body) body = strdup("");
|
if (!body) body = strdup("");
|
||||||
FunCurlBuf buf = {NULL, 0};
|
FunCurlBuf buf = {NULL, 0};
|
||||||
CURL *h = curl_easy_init();
|
CURL *h = curl_easy_init();
|
||||||
if (!h) { free(url); free(body); push_value(vm, make_string("")); break; }
|
if (!h) {
|
||||||
|
free(url);
|
||||||
|
free(body);
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
curl_easy_setopt(h, CURLOPT_URL, url);
|
curl_easy_setopt(h, CURLOPT_URL, url);
|
||||||
curl_easy_setopt(h, CURLOPT_FOLLOWLOCATION, 1L);
|
curl_easy_setopt(h, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
curl_easy_setopt(h, CURLOPT_POST, 1L);
|
curl_easy_setopt(h, CURLOPT_POST, 1L);
|
||||||
|
|
@ -33,8 +42,10 @@ case OP_CURL_POST: {
|
||||||
if (buf.d) free(buf.d);
|
if (buf.d) free(buf.d);
|
||||||
push_value(vm, s);
|
push_value(vm, s);
|
||||||
#else
|
#else
|
||||||
Value a = pop_value(vm); free_value(a);
|
Value a = pop_value(vm);
|
||||||
Value b = pop_value(vm); free_value(b);
|
free_value(a);
|
||||||
|
Value b = pop_value(vm);
|
||||||
|
free_value(b);
|
||||||
push_value(vm, make_string(""));
|
push_value(vm, make_string(""));
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,16 @@ case OP_INI_GET_BOOL: {
|
||||||
dictionary *d = ini_get(h);
|
dictionary *d = ini_get(h);
|
||||||
int outb = def;
|
int outb = def;
|
||||||
if (d && sec && key) {
|
if (d && sec && key) {
|
||||||
char full[1024]; char alt[1024];
|
char full[1024];
|
||||||
|
char alt[1024];
|
||||||
ini_make_full_key(full, sizeof(full), sec, key);
|
ini_make_full_key(full, sizeof(full), sec, key);
|
||||||
memcpy(alt, full, sizeof(alt));
|
memcpy(alt, full, sizeof(alt));
|
||||||
for (size_t i = 0; i < sizeof(alt) && alt[i]; ++i) { if (alt[i] == ':') { alt[i] = '.'; break; } }
|
for (size_t i = 0; i < sizeof(alt) && alt[i]; ++i) {
|
||||||
|
if (alt[i] == ':') {
|
||||||
|
alt[i] = '.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
const char *s = iniparser_getstring(d, full, NULL);
|
const char *s = iniparser_getstring(d, full, NULL);
|
||||||
if (!s) s = iniparser_getstring(d, alt, NULL);
|
if (!s) s = iniparser_getstring(d, alt, NULL);
|
||||||
if (s) {
|
if (s) {
|
||||||
|
|
@ -35,27 +41,37 @@ case OP_INI_GET_BOOL: {
|
||||||
size_t n = strlen(s);
|
size_t n = strlen(s);
|
||||||
if (n >= 2 && ((s[0] == '"' && s[n - 1] == '"') || (s[0] == '\'' && s[n - 1] == '\''))) {
|
if (n >= 2 && ((s[0] == '"' && s[n - 1] == '"') || (s[0] == '\'' && s[n - 1] == '\''))) {
|
||||||
size_t copy = (n - 2) < sizeof(buf) - 1 ? (n - 2) : sizeof(buf) - 1;
|
size_t copy = (n - 2) < sizeof(buf) - 1 ? (n - 2) : sizeof(buf) - 1;
|
||||||
memcpy(buf, s+1, copy); buf[copy] = '\0';
|
memcpy(buf, s + 1, copy);
|
||||||
|
buf[copy] = '\0';
|
||||||
s = buf;
|
s = buf;
|
||||||
}
|
}
|
||||||
/* trim spaces */
|
/* trim spaces */
|
||||||
while (*s && (unsigned char)*s <= ' ') s++;
|
while (*s && (unsigned char)*s <= ' ')
|
||||||
|
s++;
|
||||||
/* lower copy for textual booleans */
|
/* lower copy for textual booleans */
|
||||||
char lb[256]; size_t li=0; for (; s[li] && li < sizeof(lb)-1; ++li) lb[li] = (char)tolower((unsigned char)s[li]); lb[li]='\0';
|
char lb[256];
|
||||||
|
size_t li = 0;
|
||||||
|
for (; s[li] && li < sizeof(lb) - 1; ++li)
|
||||||
|
lb[li] = (char)tolower((unsigned char)s[li]);
|
||||||
|
lb[li] = '\0';
|
||||||
if (strcmp(lb, "true") == 0 || strcmp(lb, "yes") == 0 || strcmp(lb, "on") == 0) {
|
if (strcmp(lb, "true") == 0 || strcmp(lb, "yes") == 0 || strcmp(lb, "on") == 0) {
|
||||||
outb = 1;
|
outb = 1;
|
||||||
} else if (strcmp(lb, "false") == 0 || strcmp(lb, "no") == 0 || strcmp(lb, "off") == 0) {
|
} else if (strcmp(lb, "false") == 0 || strcmp(lb, "no") == 0 || strcmp(lb, "off") == 0) {
|
||||||
outb = 0;
|
outb = 0;
|
||||||
} else {
|
} else {
|
||||||
/* numeric */
|
/* numeric */
|
||||||
char *endp=NULL; long v = strtol(lb, &endp, 10);
|
char *endp = NULL;
|
||||||
|
long v = strtol(lb, &endp, 10);
|
||||||
outb = (endp && endp != lb) ? (v != 0) : def;
|
outb = (endp && endp != lb) ? (v != 0) : def;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
outb = def;
|
outb = def;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free_value(vdef); free_value(vkey); free_value(vsec); free_value(vh);
|
free_value(vdef);
|
||||||
|
free_value(vkey);
|
||||||
|
free_value(vsec);
|
||||||
|
free_value(vh);
|
||||||
push_value(vm, make_int(outb ? 1 : 0));
|
push_value(vm, make_int(outb ? 1 : 0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,16 @@ case OP_INI_GET_DOUBLE: {
|
||||||
dictionary *d = ini_get(h);
|
dictionary *d = ini_get(h);
|
||||||
double outd = def;
|
double outd = def;
|
||||||
if (d && sec && key) {
|
if (d && sec && key) {
|
||||||
char full[1024]; char alt[1024];
|
char full[1024];
|
||||||
|
char alt[1024];
|
||||||
ini_make_full_key(full, sizeof(full), sec, key);
|
ini_make_full_key(full, sizeof(full), sec, key);
|
||||||
memcpy(alt, full, sizeof(alt));
|
memcpy(alt, full, sizeof(alt));
|
||||||
for (size_t i = 0; i < sizeof(alt) && alt[i]; ++i) { if (alt[i] == ':') { alt[i] = '.'; break; } }
|
for (size_t i = 0; i < sizeof(alt) && alt[i]; ++i) {
|
||||||
|
if (alt[i] == ':') {
|
||||||
|
alt[i] = '.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
const char *s = iniparser_getstring(d, full, NULL);
|
const char *s = iniparser_getstring(d, full, NULL);
|
||||||
if (!s) s = iniparser_getstring(d, alt, NULL);
|
if (!s) s = iniparser_getstring(d, alt, NULL);
|
||||||
if (s) {
|
if (s) {
|
||||||
|
|
@ -34,18 +40,26 @@ case OP_INI_GET_DOUBLE: {
|
||||||
size_t n = strlen(s);
|
size_t n = strlen(s);
|
||||||
if (n >= 2 && ((s[0] == '"' && s[n - 1] == '"') || (s[0] == '\'' && s[n - 1] == '\''))) {
|
if (n >= 2 && ((s[0] == '"' && s[n - 1] == '"') || (s[0] == '\'' && s[n - 1] == '\''))) {
|
||||||
size_t copy = (n - 2) < sizeof(buf) - 1 ? (n - 2) : sizeof(buf) - 1;
|
size_t copy = (n - 2) < sizeof(buf) - 1 ? (n - 2) : sizeof(buf) - 1;
|
||||||
memcpy(buf, s+1, copy); buf[copy] = '\0';
|
memcpy(buf, s + 1, copy);
|
||||||
|
buf[copy] = '\0';
|
||||||
s = buf;
|
s = buf;
|
||||||
}
|
}
|
||||||
while (*s && (unsigned char)*s <= ' ') s++;
|
while (*s && (unsigned char)*s <= ' ')
|
||||||
|
s++;
|
||||||
char *endp = NULL;
|
char *endp = NULL;
|
||||||
double v = strtod(s, &endp);
|
double v = strtod(s, &endp);
|
||||||
if (endp && endp != s) outd = v; else outd = def;
|
if (endp && endp != s)
|
||||||
|
outd = v;
|
||||||
|
else
|
||||||
|
outd = def;
|
||||||
} else {
|
} else {
|
||||||
outd = def;
|
outd = def;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free_value(vdef); free_value(vkey); free_value(vsec); free_value(vh);
|
free_value(vdef);
|
||||||
|
free_value(vkey);
|
||||||
|
free_value(vsec);
|
||||||
|
free_value(vh);
|
||||||
push_value(vm, make_float(outd));
|
push_value(vm, make_float(outd));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,16 @@ case OP_INI_GET_INT: {
|
||||||
dictionary *d = ini_get(h);
|
dictionary *d = ini_get(h);
|
||||||
int outi = def;
|
int outi = def;
|
||||||
if (d && sec && key) {
|
if (d && sec && key) {
|
||||||
char full[1024]; char alt[1024];
|
char full[1024];
|
||||||
|
char alt[1024];
|
||||||
ini_make_full_key(full, sizeof(full), sec, key);
|
ini_make_full_key(full, sizeof(full), sec, key);
|
||||||
memcpy(alt, full, sizeof(alt));
|
memcpy(alt, full, sizeof(alt));
|
||||||
for (size_t i = 0; i < sizeof(alt) && alt[i]; ++i) { if (alt[i] == ':') { alt[i] = '.'; break; } }
|
for (size_t i = 0; i < sizeof(alt) && alt[i]; ++i) {
|
||||||
|
if (alt[i] == ':') {
|
||||||
|
alt[i] = '.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
const char *s = iniparser_getstring(d, full, NULL);
|
const char *s = iniparser_getstring(d, full, NULL);
|
||||||
if (!s) s = iniparser_getstring(d, alt, NULL);
|
if (!s) s = iniparser_getstring(d, alt, NULL);
|
||||||
if (s) {
|
if (s) {
|
||||||
|
|
@ -35,19 +41,27 @@ case OP_INI_GET_INT: {
|
||||||
size_t n = strlen(s);
|
size_t n = strlen(s);
|
||||||
if (n >= 2 && ((s[0] == '"' && s[n - 1] == '"') || (s[0] == '\'' && s[n - 1] == '\''))) {
|
if (n >= 2 && ((s[0] == '"' && s[n - 1] == '"') || (s[0] == '\'' && s[n - 1] == '\''))) {
|
||||||
size_t copy = (n - 2) < sizeof(buf) - 1 ? (n - 2) : sizeof(buf) - 1;
|
size_t copy = (n - 2) < sizeof(buf) - 1 ? (n - 2) : sizeof(buf) - 1;
|
||||||
memcpy(buf, s+1, copy); buf[copy] = '\0';
|
memcpy(buf, s + 1, copy);
|
||||||
|
buf[copy] = '\0';
|
||||||
s = buf;
|
s = buf;
|
||||||
}
|
}
|
||||||
/* skip leading spaces */
|
/* skip leading spaces */
|
||||||
while (*s && (unsigned char)*s <= ' ') s++;
|
while (*s && (unsigned char)*s <= ' ')
|
||||||
|
s++;
|
||||||
char *endp = NULL;
|
char *endp = NULL;
|
||||||
long v = strtol(s, &endp, 10);
|
long v = strtol(s, &endp, 10);
|
||||||
if (endp && endp != s) outi = (int)v; else outi = def;
|
if (endp && endp != s)
|
||||||
|
outi = (int)v;
|
||||||
|
else
|
||||||
|
outi = def;
|
||||||
} else {
|
} else {
|
||||||
outi = def;
|
outi = def;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free_value(vdef); free_value(vkey); free_value(vsec); free_value(vh);
|
free_value(vdef);
|
||||||
|
free_value(vkey);
|
||||||
|
free_value(vsec);
|
||||||
|
free_value(vh);
|
||||||
push_value(vm, make_int(outi));
|
push_value(vm, make_int(outi));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,19 @@ case OP_INI_GET_STRING: {
|
||||||
dictionary *d = ini_get(h);
|
dictionary *d = ini_get(h);
|
||||||
const char *res = def;
|
const char *res = def;
|
||||||
if (d && sec && key) {
|
if (d && sec && key) {
|
||||||
char full[1024]; char alt[1024];
|
char full[1024];
|
||||||
|
char alt[1024];
|
||||||
ini_make_full_key(full, sizeof(full), sec, key);
|
ini_make_full_key(full, sizeof(full), sec, key);
|
||||||
/* Build alternate with dot separator for robustness */
|
/* Build alternate with dot separator for robustness */
|
||||||
ini_make_full_key(alt, sizeof(alt), sec, key);
|
ini_make_full_key(alt, sizeof(alt), sec, key);
|
||||||
size_t flen = strlen(full);
|
size_t flen = strlen(full);
|
||||||
if (flen < sizeof(alt) && flen > 0) { /* create dot version in alt */
|
if (flen < sizeof(alt) && flen > 0) { /* create dot version in alt */
|
||||||
memcpy(alt, full, flen + 1);
|
memcpy(alt, full, flen + 1);
|
||||||
for (size_t i = 0; i < flen; ++i) if (alt[i] == ':') { alt[i] = '.'; break; }
|
for (size_t i = 0; i < flen; ++i)
|
||||||
|
if (alt[i] == ':') {
|
||||||
|
alt[i] = '.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const char *s = iniparser_getstring(d, full, def);
|
const char *s = iniparser_getstring(d, full, def);
|
||||||
if (s == def) { /* not found, try alternate dot form */
|
if (s == def) { /* not found, try alternate dot form */
|
||||||
|
|
@ -38,7 +43,10 @@ case OP_INI_GET_STRING: {
|
||||||
}
|
}
|
||||||
res = s ? s : "";
|
res = s ? s : "";
|
||||||
}
|
}
|
||||||
free_value(vdef); free_value(vkey); free_value(vsec); free_value(vh);
|
free_value(vdef);
|
||||||
|
free_value(vkey);
|
||||||
|
free_value(vsec);
|
||||||
|
free_value(vh);
|
||||||
push_value(vm, make_string(res));
|
push_value(vm, make_string(res));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,22 +10,22 @@
|
||||||
#ifdef FUN_WITH_INI
|
#ifdef FUN_WITH_INI
|
||||||
#if defined(__has_include)
|
#if defined(__has_include)
|
||||||
#if __has_include(<iniparser/iniparser.h>)
|
#if __has_include(<iniparser/iniparser.h>)
|
||||||
# include <iniparser/iniparser.h>
|
|
||||||
#include <iniparser/dictionary.h>
|
#include <iniparser/dictionary.h>
|
||||||
|
#include <iniparser/iniparser.h>
|
||||||
#elif __has_include(<iniparser.h>)
|
#elif __has_include(<iniparser.h>)
|
||||||
# include <iniparser.h>
|
|
||||||
#include <dictionary.h>
|
#include <dictionary.h>
|
||||||
|
#include <iniparser.h>
|
||||||
#else
|
#else
|
||||||
#error "iniparser headers not found"
|
#error "iniparser headers not found"
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
# include <iniparser/iniparser.h>
|
|
||||||
#include <iniparser/dictionary.h>
|
#include <iniparser/dictionary.h>
|
||||||
|
#include <iniparser/iniparser.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "handles.h"
|
#include "handles.h"
|
||||||
|
|
||||||
|
|
@ -34,7 +34,11 @@ IniSlot g_ini[64];
|
||||||
int ini_alloc_handle(dictionary *d) {
|
int ini_alloc_handle(dictionary *d) {
|
||||||
if (!d) return 0;
|
if (!d) return 0;
|
||||||
for (int i = 1; i < (int)(sizeof(g_ini) / sizeof(g_ini[0])); ++i) {
|
for (int i = 1; i < (int)(sizeof(g_ini) / sizeof(g_ini[0])); ++i) {
|
||||||
if (!g_ini[i].in_use) { g_ini[i].in_use = 1; g_ini[i].dict = d; return i; }
|
if (!g_ini[i].in_use) {
|
||||||
|
g_ini[i].in_use = 1;
|
||||||
|
g_ini[i].dict = d;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,21 +15,24 @@
|
||||||
#ifdef FUN_WITH_INI
|
#ifdef FUN_WITH_INI
|
||||||
#if defined(__has_include)
|
#if defined(__has_include)
|
||||||
#if __has_include(<iniparser/iniparser.h>)
|
#if __has_include(<iniparser/iniparser.h>)
|
||||||
# include <iniparser/iniparser.h>
|
|
||||||
#include <iniparser/dictionary.h>
|
#include <iniparser/dictionary.h>
|
||||||
|
#include <iniparser/iniparser.h>
|
||||||
#elif __has_include(<iniparser.h>)
|
#elif __has_include(<iniparser.h>)
|
||||||
# include <iniparser.h>
|
|
||||||
#include <dictionary.h>
|
#include <dictionary.h>
|
||||||
|
#include <iniparser.h>
|
||||||
#else
|
#else
|
||||||
#error "iniparser headers not found"
|
#error "iniparser headers not found"
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
# include <iniparser/iniparser.h>
|
|
||||||
#include <iniparser/dictionary.h>
|
#include <iniparser/dictionary.h>
|
||||||
|
#include <iniparser/iniparser.h>
|
||||||
#endif
|
#endif
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
typedef struct { dictionary *dict; int in_use; } IniSlot;
|
typedef struct {
|
||||||
|
dictionary *dict;
|
||||||
|
int in_use;
|
||||||
|
} IniSlot;
|
||||||
|
|
||||||
/* Single global registry (defined in handles.c) */
|
/* Single global registry (defined in handles.c) */
|
||||||
extern IniSlot g_ini[64];
|
extern IniSlot g_ini[64];
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,9 @@ case OP_INI_LOAD: {
|
||||||
dictionary *d = iniparser_load(path);
|
dictionary *d = iniparser_load(path);
|
||||||
if (d) {
|
if (d) {
|
||||||
h = ini_alloc_handle(d);
|
h = ini_alloc_handle(d);
|
||||||
if (!h) { iniparser_freedict(d); }
|
if (!h) {
|
||||||
|
iniparser_freedict(d);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free_value(vpath);
|
free_value(vpath);
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,14 @@ case OP_INI_SAVE: {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
if (d && path) {
|
if (d && path) {
|
||||||
FILE *f = fopen(path, "w");
|
FILE *f = fopen(path, "w");
|
||||||
if (f) { iniparser_dump_ini(d, f); fclose(f); ok = 1; }
|
if (f) {
|
||||||
|
iniparser_dump_ini(d, f);
|
||||||
|
fclose(f);
|
||||||
|
ok = 1;
|
||||||
}
|
}
|
||||||
free_value(vpath); free_value(vh);
|
}
|
||||||
|
free_value(vpath);
|
||||||
|
free_value(vh);
|
||||||
push_value(vm, make_int(ok));
|
push_value(vm, make_int(ok));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,16 @@ case OP_INI_SET: {
|
||||||
if (d && sec && key) {
|
if (d && sec && key) {
|
||||||
char *valstr = value_to_string_alloc(&vval);
|
char *valstr = value_to_string_alloc(&vval);
|
||||||
if (valstr) {
|
if (valstr) {
|
||||||
char full[1024]; char alt[1024];
|
char full[1024];
|
||||||
|
char alt[1024];
|
||||||
ini_make_full_key(full, sizeof(full), sec, key);
|
ini_make_full_key(full, sizeof(full), sec, key);
|
||||||
memcpy(alt, full, sizeof(alt));
|
memcpy(alt, full, sizeof(alt));
|
||||||
for (size_t i = 0; i < sizeof(alt) && alt[i]; ++i) { if (alt[i] == ':') { alt[i] = '.'; break; } }
|
for (size_t i = 0; i < sizeof(alt) && alt[i]; ++i) {
|
||||||
|
if (alt[i] == ':') {
|
||||||
|
alt[i] = '.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* iniparser 4.x does not expose iniparser_set; use dictionary_set */
|
/* iniparser 4.x does not expose iniparser_set; use dictionary_set */
|
||||||
if (dictionary_set(d, full, valstr) == 0) {
|
if (dictionary_set(d, full, valstr) == 0) {
|
||||||
ok = 1; /* 0 means success */
|
ok = 1; /* 0 means success */
|
||||||
|
|
@ -36,7 +42,10 @@ case OP_INI_SET: {
|
||||||
free(valstr);
|
free(valstr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free_value(vval); free_value(vkey); free_value(vsec); free_value(vh);
|
free_value(vval);
|
||||||
|
free_value(vkey);
|
||||||
|
free_value(vsec);
|
||||||
|
free_value(vh);
|
||||||
push_value(vm, make_int(ok));
|
push_value(vm, make_int(ok));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,9 @@ case OP_INI_GET_STRING: {
|
||||||
Value vkey = pop_value(vm);
|
Value vkey = pop_value(vm);
|
||||||
Value vsec = pop_value(vm);
|
Value vsec = pop_value(vm);
|
||||||
Value vh = pop_value(vm);
|
Value vh = pop_value(vm);
|
||||||
free_value(vh); free_value(vsec); free_value(vkey);
|
free_value(vh);
|
||||||
|
free_value(vsec);
|
||||||
|
free_value(vkey);
|
||||||
/* cannot convert here; return empty string */
|
/* cannot convert here; return empty string */
|
||||||
push_value(vm, make_string(""));
|
push_value(vm, make_string(""));
|
||||||
free_value(vdef);
|
free_value(vdef);
|
||||||
|
|
@ -41,7 +43,9 @@ case OP_INI_GET_INT: {
|
||||||
Value vkey = pop_value(vm);
|
Value vkey = pop_value(vm);
|
||||||
Value vsec = pop_value(vm);
|
Value vsec = pop_value(vm);
|
||||||
Value vh = pop_value(vm);
|
Value vh = pop_value(vm);
|
||||||
free_value(vh); free_value(vsec); free_value(vkey);
|
free_value(vh);
|
||||||
|
free_value(vsec);
|
||||||
|
free_value(vkey);
|
||||||
(void)vdef; /* unused */
|
(void)vdef; /* unused */
|
||||||
push_value(vm, make_int(0));
|
push_value(vm, make_int(0));
|
||||||
fun_vm_fprintf(stderr, "Runtime error: INI support disabled (rebuild with -DFUN_WITH_INI=ON)\n");
|
fun_vm_fprintf(stderr, "Runtime error: INI support disabled (rebuild with -DFUN_WITH_INI=ON)\n");
|
||||||
|
|
@ -53,7 +57,9 @@ case OP_INI_GET_DOUBLE: {
|
||||||
Value vkey = pop_value(vm);
|
Value vkey = pop_value(vm);
|
||||||
Value vsec = pop_value(vm);
|
Value vsec = pop_value(vm);
|
||||||
Value vh = pop_value(vm);
|
Value vh = pop_value(vm);
|
||||||
free_value(vh); free_value(vsec); free_value(vkey);
|
free_value(vh);
|
||||||
|
free_value(vsec);
|
||||||
|
free_value(vkey);
|
||||||
(void)vdef; /* unused */
|
(void)vdef; /* unused */
|
||||||
push_value(vm, make_float(0.0));
|
push_value(vm, make_float(0.0));
|
||||||
fun_vm_fprintf(stderr, "Runtime error: INI support disabled (rebuild with -DFUN_WITH_INI=ON)\n");
|
fun_vm_fprintf(stderr, "Runtime error: INI support disabled (rebuild with -DFUN_WITH_INI=ON)\n");
|
||||||
|
|
@ -65,7 +71,9 @@ case OP_INI_GET_BOOL: {
|
||||||
Value vkey = pop_value(vm);
|
Value vkey = pop_value(vm);
|
||||||
Value vsec = pop_value(vm);
|
Value vsec = pop_value(vm);
|
||||||
Value vh = pop_value(vm);
|
Value vh = pop_value(vm);
|
||||||
free_value(vh); free_value(vsec); free_value(vkey);
|
free_value(vh);
|
||||||
|
free_value(vsec);
|
||||||
|
free_value(vkey);
|
||||||
(void)vdef; /* unused */
|
(void)vdef; /* unused */
|
||||||
push_value(vm, make_int(0));
|
push_value(vm, make_int(0));
|
||||||
fun_vm_fprintf(stderr, "Runtime error: INI support disabled (rebuild with -DFUN_WITH_INI=ON)\n");
|
fun_vm_fprintf(stderr, "Runtime error: INI support disabled (rebuild with -DFUN_WITH_INI=ON)\n");
|
||||||
|
|
@ -78,7 +86,10 @@ case OP_INI_SET: {
|
||||||
Value vkey = pop_value(vm);
|
Value vkey = pop_value(vm);
|
||||||
Value vsec = pop_value(vm);
|
Value vsec = pop_value(vm);
|
||||||
Value vh = pop_value(vm);
|
Value vh = pop_value(vm);
|
||||||
free_value(vh); free_value(vsec); free_value(vkey); free_value(vval);
|
free_value(vh);
|
||||||
|
free_value(vsec);
|
||||||
|
free_value(vkey);
|
||||||
|
free_value(vval);
|
||||||
fun_vm_fprintf(stderr, "Runtime error: INI support disabled (rebuild with -DFUN_WITH_INI=ON)\n");
|
fun_vm_fprintf(stderr, "Runtime error: INI support disabled (rebuild with -DFUN_WITH_INI=ON)\n");
|
||||||
push_value(vm, make_int(0));
|
push_value(vm, make_int(0));
|
||||||
break;
|
break;
|
||||||
|
|
@ -88,7 +99,9 @@ case OP_INI_UNSET: {
|
||||||
Value vkey = pop_value(vm);
|
Value vkey = pop_value(vm);
|
||||||
Value vsec = pop_value(vm);
|
Value vsec = pop_value(vm);
|
||||||
Value vh = pop_value(vm);
|
Value vh = pop_value(vm);
|
||||||
free_value(vh); free_value(vsec); free_value(vkey);
|
free_value(vh);
|
||||||
|
free_value(vsec);
|
||||||
|
free_value(vkey);
|
||||||
fun_vm_fprintf(stderr, "Runtime error: INI support disabled (rebuild with -DFUN_WITH_INI=ON)\n");
|
fun_vm_fprintf(stderr, "Runtime error: INI support disabled (rebuild with -DFUN_WITH_INI=ON)\n");
|
||||||
push_value(vm, make_int(0));
|
push_value(vm, make_int(0));
|
||||||
break;
|
break;
|
||||||
|
|
@ -97,7 +110,8 @@ case OP_INI_UNSET: {
|
||||||
case OP_INI_SAVE: {
|
case OP_INI_SAVE: {
|
||||||
Value vpath = pop_value(vm);
|
Value vpath = pop_value(vm);
|
||||||
Value vh = pop_value(vm);
|
Value vh = pop_value(vm);
|
||||||
free_value(vh); free_value(vpath);
|
free_value(vh);
|
||||||
|
free_value(vpath);
|
||||||
fun_vm_fprintf(stderr, "Runtime error: INI support disabled (rebuild with -DFUN_WITH_INI=ON)\n");
|
fun_vm_fprintf(stderr, "Runtime error: INI support disabled (rebuild with -DFUN_WITH_INI=ON)\n");
|
||||||
push_value(vm, make_int(0));
|
push_value(vm, make_int(0));
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -20,16 +20,24 @@ case OP_INI_UNSET: {
|
||||||
const char *sec = (vsec.type == VAL_STRING) ? vsec.s : NULL;
|
const char *sec = (vsec.type == VAL_STRING) ? vsec.s : NULL;
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
if (d && sec && key) {
|
if (d && sec && key) {
|
||||||
char full[1024]; char alt[1024];
|
char full[1024];
|
||||||
|
char alt[1024];
|
||||||
ini_make_full_key(full, sizeof(full), sec, key);
|
ini_make_full_key(full, sizeof(full), sec, key);
|
||||||
memcpy(alt, full, sizeof(alt));
|
memcpy(alt, full, sizeof(alt));
|
||||||
for (size_t i = 0; i < sizeof(alt) && alt[i]; ++i) { if (alt[i] == ':') { alt[i] = '.'; break; } }
|
for (size_t i = 0; i < sizeof(alt) && alt[i]; ++i) {
|
||||||
|
if (alt[i] == ':') {
|
||||||
|
alt[i] = '.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* iniparser 4.2.6 dictionary_unset returns void; remove both forms */
|
/* iniparser 4.2.6 dictionary_unset returns void; remove both forms */
|
||||||
dictionary_unset(d, full);
|
dictionary_unset(d, full);
|
||||||
dictionary_unset(d, alt);
|
dictionary_unset(d, alt);
|
||||||
ok = 1;
|
ok = 1;
|
||||||
}
|
}
|
||||||
free_value(vkey); free_value(vsec); free_value(vh);
|
free_value(vkey);
|
||||||
|
free_value(vsec);
|
||||||
|
free_value(vh);
|
||||||
push_value(vm, make_int(ok));
|
push_value(vm, make_int(ok));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,18 +33,39 @@
|
||||||
|
|
||||||
case OP_READ_FILE: {
|
case OP_READ_FILE: {
|
||||||
Value path = pop_value(vm);
|
Value path = pop_value(vm);
|
||||||
if (path.type != VAL_STRING) { fprintf(stderr, "READ_FILE expects string\n"); exit(1); }
|
if (path.type != VAL_STRING) {
|
||||||
|
fprintf(stderr, "READ_FILE expects string\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
const char *p = path.s ? path.s : "";
|
const char *p = path.s ? path.s : "";
|
||||||
FILE *f = fopen(p, "rb");
|
FILE *f = fopen(p, "rb");
|
||||||
if (!f) { free_value(path); push_value(vm, make_string("")); break; }
|
if (!f) {
|
||||||
if (fseek(f, 0, SEEK_END) != 0) { fclose(f); free_value(path); push_value(vm, make_string("")); break; }
|
free_value(path);
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (fseek(f, 0, SEEK_END) != 0) {
|
||||||
|
fclose(f);
|
||||||
|
free_value(path);
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
long sz = ftell(f);
|
long sz = ftell(f);
|
||||||
if (sz < 0) { fclose(f); free_value(path); push_value(vm, make_string("")); break; }
|
if (sz < 0) {
|
||||||
|
fclose(f);
|
||||||
|
free_value(path);
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
rewind(f);
|
rewind(f);
|
||||||
char *buf = (char *)malloc((size_t)sz + 1);
|
char *buf = (char *)malloc((size_t)sz + 1);
|
||||||
size_t n = buf ? fread(buf, 1, (size_t)sz, f) : 0;
|
size_t n = buf ? fread(buf, 1, (size_t)sz, f) : 0;
|
||||||
fclose(f);
|
fclose(f);
|
||||||
if (!buf) { free_value(path); push_value(vm, make_string("")); break; }
|
if (!buf) {
|
||||||
|
free_value(path);
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
buf[n] = '\0';
|
buf[n] = '\0';
|
||||||
Value out = make_string(buf);
|
Value out = make_string(buf);
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,10 @@
|
||||||
case OP_WRITE_FILE: {
|
case OP_WRITE_FILE: {
|
||||||
Value data = pop_value(vm);
|
Value data = pop_value(vm);
|
||||||
Value path = pop_value(vm);
|
Value path = pop_value(vm);
|
||||||
if (path.type != VAL_STRING || data.type != VAL_STRING) { fprintf(stderr, "WRITE_FILE expects (string, string)\n"); exit(1); }
|
if (path.type != VAL_STRING || data.type != VAL_STRING) {
|
||||||
|
fprintf(stderr, "WRITE_FILE expects (string, string)\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
const char *p = path.s ? path.s : "";
|
const char *p = path.s ? path.s : "";
|
||||||
FILE *f = fopen(p, "wb");
|
FILE *f = fopen(p, "wb");
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,22 @@ case OP_JSON_FROM_FILE: {
|
||||||
Value vpath = pop_value(vm);
|
Value vpath = pop_value(vm);
|
||||||
char *path = value_to_string_alloc(&vpath);
|
char *path = value_to_string_alloc(&vpath);
|
||||||
free_value(vpath);
|
free_value(vpath);
|
||||||
if (!path) { push_value(vm, make_nil()); break; }
|
if (!path) {
|
||||||
|
push_value(vm, make_nil());
|
||||||
|
break;
|
||||||
|
}
|
||||||
json_object *root = json_object_from_file(path);
|
json_object *root = json_object_from_file(path);
|
||||||
free(path);
|
free(path);
|
||||||
if (!root) { push_value(vm, make_nil()); break; }
|
if (!root) {
|
||||||
|
push_value(vm, make_nil());
|
||||||
|
break;
|
||||||
|
}
|
||||||
Value v = json_to_fun(root);
|
Value v = json_to_fun(root);
|
||||||
push_value(vm, v);
|
push_value(vm, v);
|
||||||
json_object_put(root);
|
json_object_put(root);
|
||||||
#else
|
#else
|
||||||
Value vpath = pop_value(vm); free_value(vpath);
|
Value vpath = pop_value(vm);
|
||||||
|
free_value(vpath);
|
||||||
push_value(vm, make_nil());
|
push_value(vm, make_nil());
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,10 @@ case OP_JSON_PARSE: {
|
||||||
Value text = pop_value(vm);
|
Value text = pop_value(vm);
|
||||||
char *s = value_to_string_alloc(&text);
|
char *s = value_to_string_alloc(&text);
|
||||||
free_value(text);
|
free_value(text);
|
||||||
if (!s) { push_value(vm, make_nil()); break; }
|
if (!s) {
|
||||||
|
push_value(vm, make_nil());
|
||||||
|
break;
|
||||||
|
}
|
||||||
struct json_tokener *tok = json_tokener_new();
|
struct json_tokener *tok = json_tokener_new();
|
||||||
json_object *root = json_tokener_parse_ex(tok, s, (int)strlen(s));
|
json_object *root = json_tokener_parse_ex(tok, s, (int)strlen(s));
|
||||||
enum json_tokener_error jerr = json_tokener_get_error(tok);
|
enum json_tokener_error jerr = json_tokener_get_error(tok);
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,10 @@ case OP_JSON_STRINGIFY: {
|
||||||
free_value(any);
|
free_value(any);
|
||||||
#else
|
#else
|
||||||
/* Fallback: consume two args, push "null" */
|
/* Fallback: consume two args, push "null" */
|
||||||
Value vpretty = pop_value(vm); free_value(vpretty);
|
Value vpretty = pop_value(vm);
|
||||||
Value any = pop_value(vm); free_value(any);
|
free_value(vpretty);
|
||||||
|
Value any = pop_value(vm);
|
||||||
|
free_value(any);
|
||||||
push_value(vm, make_string("null"));
|
push_value(vm, make_string("null"));
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,11 @@ case OP_JSON_TO_FILE: {
|
||||||
int pretty = (vpretty.type == VAL_BOOL || vpretty.type == VAL_INT) ? (vpretty.i != 0) : 0;
|
int pretty = (vpretty.type == VAL_BOOL || vpretty.type == VAL_INT) ? (vpretty.i != 0) : 0;
|
||||||
free_value(vpretty);
|
free_value(vpretty);
|
||||||
free_value(vpath);
|
free_value(vpath);
|
||||||
if (!path) { free_value(any); push_value(vm, make_int(0)); break; }
|
if (!path) {
|
||||||
|
free_value(any);
|
||||||
|
push_value(vm, make_int(0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
json_object *j = fun_to_json(&any);
|
json_object *j = fun_to_json(&any);
|
||||||
int flags = pretty ? JSON_C_TO_STRING_PRETTY : JSON_C_TO_STRING_PLAIN;
|
int flags = pretty ? JSON_C_TO_STRING_PRETTY : JSON_C_TO_STRING_PLAIN;
|
||||||
int rc = json_object_to_file_ext(path, j, flags);
|
int rc = json_object_to_file_ext(path, j, flags);
|
||||||
|
|
@ -28,9 +32,12 @@ case OP_JSON_TO_FILE: {
|
||||||
free_value(any);
|
free_value(any);
|
||||||
push_value(vm, make_int(rc == 0 ? 1 : 0));
|
push_value(vm, make_int(rc == 0 ? 1 : 0));
|
||||||
#else
|
#else
|
||||||
Value vpretty = pop_value(vm); free_value(vpretty);
|
Value vpretty = pop_value(vm);
|
||||||
Value any = pop_value(vm); free_value(any);
|
free_value(vpretty);
|
||||||
Value vpath = pop_value(vm); free_value(vpath);
|
Value any = pop_value(vm);
|
||||||
|
free_value(any);
|
||||||
|
Value vpath = pop_value(vm);
|
||||||
|
free_value(vpath);
|
||||||
push_value(vm, make_int(0));
|
push_value(vm, make_int(0));
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,16 @@ case OP_LIBRESSL_MD5: {
|
||||||
Value vdata = pop_value(vm);
|
Value vdata = pop_value(vm);
|
||||||
char *s = value_to_string_alloc(&vdata);
|
char *s = value_to_string_alloc(&vdata);
|
||||||
free_value(vdata);
|
free_value(vdata);
|
||||||
if (!s) { push_value(vm, make_string("")); break; }
|
if (!s) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
char *hex = fun_libressl_md5_hex((const unsigned char *)s, strlen(s));
|
char *hex = fun_libressl_md5_hex((const unsigned char *)s, strlen(s));
|
||||||
free(s);
|
free(s);
|
||||||
if (!hex) { push_value(vm, make_string("")); break; }
|
if (!hex) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
Value out = make_string(hex);
|
Value out = make_string(hex);
|
||||||
free(hex);
|
free(hex);
|
||||||
push_value(vm, out);
|
push_value(vm, out);
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,16 @@ case OP_LIBRESSL_RIPEMD160: {
|
||||||
Value vdata = pop_value(vm);
|
Value vdata = pop_value(vm);
|
||||||
char *s = value_to_string_alloc(&vdata);
|
char *s = value_to_string_alloc(&vdata);
|
||||||
free_value(vdata);
|
free_value(vdata);
|
||||||
if (!s) { push_value(vm, make_string("")); break; }
|
if (!s) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
char *hex = fun_libressl_ripemd160_hex((const unsigned char *)s, strlen(s));
|
char *hex = fun_libressl_ripemd160_hex((const unsigned char *)s, strlen(s));
|
||||||
free(s);
|
free(s);
|
||||||
if (!hex) { push_value(vm, make_string("")); break; }
|
if (!hex) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
Value out = make_string(hex);
|
Value out = make_string(hex);
|
||||||
free(hex);
|
free(hex);
|
||||||
push_value(vm, out);
|
push_value(vm, out);
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,16 @@ case OP_LIBRESSL_SHA256: {
|
||||||
Value vdata = pop_value(vm);
|
Value vdata = pop_value(vm);
|
||||||
char *s = value_to_string_alloc(&vdata);
|
char *s = value_to_string_alloc(&vdata);
|
||||||
free_value(vdata);
|
free_value(vdata);
|
||||||
if (!s) { push_value(vm, make_string("")); break; }
|
if (!s) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
char *hex = fun_libressl_sha256_hex((const unsigned char *)s, strlen(s));
|
char *hex = fun_libressl_sha256_hex((const unsigned char *)s, strlen(s));
|
||||||
free(s);
|
free(s);
|
||||||
if (!hex) { push_value(vm, make_string("")); break; }
|
if (!hex) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
Value out = make_string(hex);
|
Value out = make_string(hex);
|
||||||
free(hex);
|
free(hex);
|
||||||
push_value(vm, out);
|
push_value(vm, out);
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,16 @@ case OP_LIBRESSL_SHA512: {
|
||||||
Value vdata = pop_value(vm);
|
Value vdata = pop_value(vm);
|
||||||
char *s = value_to_string_alloc(&vdata);
|
char *s = value_to_string_alloc(&vdata);
|
||||||
free_value(vdata);
|
free_value(vdata);
|
||||||
if (!s) { push_value(vm, make_string("")); break; }
|
if (!s) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
char *hex = fun_libressl_sha512_hex((const unsigned char *)s, strlen(s));
|
char *hex = fun_libressl_sha512_hex((const unsigned char *)s, strlen(s));
|
||||||
free(s);
|
free(s);
|
||||||
if (!hex) { push_value(vm, make_string("")); break; }
|
if (!hex) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
Value out = make_string(hex);
|
Value out = make_string(hex);
|
||||||
free(hex);
|
free(hex);
|
||||||
push_value(vm, out);
|
push_value(vm, out);
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@ case OP_LIBSQL_CLOSE: {
|
||||||
}
|
}
|
||||||
push_value(vm, make_nil());
|
push_value(vm, make_nil());
|
||||||
#else
|
#else
|
||||||
Value v = pop_value(vm); free_value(v);
|
Value v = pop_value(vm);
|
||||||
|
free_value(v);
|
||||||
push_value(vm, make_nil());
|
push_value(vm, make_nil());
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -21,15 +21,21 @@ case OP_LIBSQL_EXEC: {
|
||||||
free_value(vh);
|
free_value(vh);
|
||||||
free_value(vsql);
|
free_value(vsql);
|
||||||
LibSqlHandle *h = libsql_reg_get(hid);
|
LibSqlHandle *h = libsql_reg_get(hid);
|
||||||
if (!h || !h->db || !sql) { if (sql) free(sql); push_value(vm, make_int(SQLITE_MISUSE)); break; }
|
if (!h || !h->db || !sql) {
|
||||||
|
if (sql) free(sql);
|
||||||
|
push_value(vm, make_int(SQLITE_MISUSE));
|
||||||
|
break;
|
||||||
|
}
|
||||||
char *errmsg = NULL;
|
char *errmsg = NULL;
|
||||||
int rc = sqlite3_exec(h->db, sql, NULL, NULL, &errmsg);
|
int rc = sqlite3_exec(h->db, sql, NULL, NULL, &errmsg);
|
||||||
if (errmsg) sqlite3_free(errmsg);
|
if (errmsg) sqlite3_free(errmsg);
|
||||||
free(sql);
|
free(sql);
|
||||||
push_value(vm, make_int(rc));
|
push_value(vm, make_int(rc));
|
||||||
#else
|
#else
|
||||||
Value v1 = pop_value(vm); free_value(v1);
|
Value v1 = pop_value(vm);
|
||||||
Value v2 = pop_value(vm); free_value(v2);
|
free_value(v1);
|
||||||
|
Value v2 = pop_value(vm);
|
||||||
|
free_value(v2);
|
||||||
push_value(vm, make_int(-1));
|
push_value(vm, make_int(-1));
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,10 @@ case OP_LIBSQL_OPEN: {
|
||||||
Value vpath = pop_value(vm);
|
Value vpath = pop_value(vm);
|
||||||
char *path = value_to_string_alloc(&vpath);
|
char *path = value_to_string_alloc(&vpath);
|
||||||
free_value(vpath);
|
free_value(vpath);
|
||||||
if (!path) { push_value(vm, make_int(0)); break; }
|
if (!path) {
|
||||||
|
push_value(vm, make_int(0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
sqlite3 *db = NULL;
|
sqlite3 *db = NULL;
|
||||||
int rc = sqlite3_open(path, &db);
|
int rc = sqlite3_open(path, &db);
|
||||||
free(path);
|
free(path);
|
||||||
|
|
@ -27,10 +30,15 @@ case OP_LIBSQL_OPEN: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
LibSqlHandle *h = libsql_reg_add(db);
|
LibSqlHandle *h = libsql_reg_add(db);
|
||||||
if (!h) { sqlite3_close(db); push_value(vm, make_int(0)); break; }
|
if (!h) {
|
||||||
|
sqlite3_close(db);
|
||||||
|
push_value(vm, make_int(0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
push_value(vm, make_int(h->id));
|
push_value(vm, make_int(h->id));
|
||||||
#else
|
#else
|
||||||
Value v = pop_value(vm); free_value(v);
|
Value v = pop_value(vm);
|
||||||
|
free_value(v);
|
||||||
push_value(vm, make_int(0));
|
push_value(vm, make_int(0));
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,11 @@ case OP_LIBSQL_QUERY: {
|
||||||
free_value(vh);
|
free_value(vh);
|
||||||
free_value(vsql);
|
free_value(vsql);
|
||||||
LibSqlHandle *h = libsql_reg_get(hid);
|
LibSqlHandle *h = libsql_reg_get(hid);
|
||||||
if (!h || !h->db || !sql) { if (sql) free(sql); push_value(vm, make_array_from_values(NULL, 0)); break; }
|
if (!h || !h->db || !sql) {
|
||||||
|
if (sql) free(sql);
|
||||||
|
push_value(vm, make_array_from_values(NULL, 0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
sqlite3_stmt *stmt = NULL;
|
sqlite3_stmt *stmt = NULL;
|
||||||
if (sqlite3_prepare_v2(h->db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
if (sqlite3_prepare_v2(h->db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||||
free(sql);
|
free(sql);
|
||||||
|
|
@ -38,11 +42,21 @@ case OP_LIBSQL_QUERY: {
|
||||||
int type = sqlite3_column_type(stmt, i);
|
int type = sqlite3_column_type(stmt, i);
|
||||||
Value kv;
|
Value kv;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SQLITE_INTEGER: kv = make_int((int64_t)sqlite3_column_int64(stmt, i)); break;
|
case SQLITE_INTEGER:
|
||||||
case SQLITE_FLOAT: kv = make_float(sqlite3_column_double(stmt, i)); break;
|
kv = make_int((int64_t)sqlite3_column_int64(stmt, i));
|
||||||
case SQLITE_TEXT: kv = make_string((const char*)sqlite3_column_text(stmt, i)); break;
|
break;
|
||||||
case SQLITE_NULL: kv = make_nil(); break;
|
case SQLITE_FLOAT:
|
||||||
default: kv = make_nil(); break; /* ignore blobs for now */
|
kv = make_float(sqlite3_column_double(stmt, i));
|
||||||
|
break;
|
||||||
|
case SQLITE_TEXT:
|
||||||
|
kv = make_string((const char *)sqlite3_column_text(stmt, i));
|
||||||
|
break;
|
||||||
|
case SQLITE_NULL:
|
||||||
|
kv = make_nil();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
kv = make_nil();
|
||||||
|
break; /* ignore blobs for now */
|
||||||
}
|
}
|
||||||
(void)map_set(&row, name ? name : "", kv);
|
(void)map_set(&row, name ? name : "", kv);
|
||||||
}
|
}
|
||||||
|
|
@ -52,8 +66,10 @@ case OP_LIBSQL_QUERY: {
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
push_value(vm, rows);
|
push_value(vm, rows);
|
||||||
#else
|
#else
|
||||||
Value v1 = pop_value(vm); free_value(v1);
|
Value v1 = pop_value(vm);
|
||||||
Value v2 = pop_value(vm); free_value(v2);
|
free_value(v1);
|
||||||
|
Value v2 = pop_value(vm);
|
||||||
|
free_value(v2);
|
||||||
push_value(vm, make_array_from_values(NULL, 0));
|
push_value(vm, make_array_from_values(NULL, 0));
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -37,12 +37,24 @@ case OP_EQ: {
|
||||||
int eq = 0;
|
int eq = 0;
|
||||||
if (a.type == b.type) {
|
if (a.type == b.type) {
|
||||||
switch (a.type) {
|
switch (a.type) {
|
||||||
case VAL_INT: eq = (a.i == b.i); break;
|
case VAL_INT:
|
||||||
case VAL_BOOL: eq = ((a.i != 0) == (b.i != 0)); break;
|
eq = (a.i == b.i);
|
||||||
case VAL_STRING: eq = (a.s && b.s) ? (strcmp(a.s, b.s) == 0) : (a.s == b.s); break;
|
break;
|
||||||
case VAL_FUNCTION: eq = (a.fn == b.fn); break;
|
case VAL_BOOL:
|
||||||
case VAL_NIL: eq = 1; break;
|
eq = ((a.i != 0) == (b.i != 0));
|
||||||
default: eq = 0; break;
|
break;
|
||||||
|
case VAL_STRING:
|
||||||
|
eq = (a.s && b.s) ? (strcmp(a.s, b.s) == 0) : (a.s == b.s);
|
||||||
|
break;
|
||||||
|
case VAL_FUNCTION:
|
||||||
|
eq = (a.fn == b.fn);
|
||||||
|
break;
|
||||||
|
case VAL_NIL:
|
||||||
|
eq = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
eq = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* interop: bool vs int (0/1) */
|
/* interop: bool vs int (0/1) */
|
||||||
|
|
@ -55,6 +67,7 @@ case OP_EQ: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
push_value(vm, make_bool(eq));
|
push_value(vm, make_bool(eq));
|
||||||
free_value(a); free_value(b);
|
free_value(a);
|
||||||
|
free_value(b);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ case OP_GT: {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
push_value(vm, make_int(a.i > b.i ? 1 : 0));
|
push_value(vm, make_int(a.i > b.i ? 1 : 0));
|
||||||
free_value(a); free_value(b);
|
free_value(a);
|
||||||
|
free_value(b);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ case OP_GTE: {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
push_value(vm, make_int(a.i >= b.i ? 1 : 0));
|
push_value(vm, make_int(a.i >= b.i ? 1 : 0));
|
||||||
free_value(a); free_value(b);
|
free_value(a);
|
||||||
|
free_value(b);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,12 +37,24 @@ case OP_NEQ: {
|
||||||
int neq = 1;
|
int neq = 1;
|
||||||
if (a.type == b.type) {
|
if (a.type == b.type) {
|
||||||
switch (a.type) {
|
switch (a.type) {
|
||||||
case VAL_INT: neq = (a.i != b.i); break;
|
case VAL_INT:
|
||||||
case VAL_BOOL: neq = ((a.i != 0) != (b.i != 0)); break;
|
neq = (a.i != b.i);
|
||||||
case VAL_STRING: neq = (a.s && b.s) ? (strcmp(a.s, b.s) != 0) : (a.s != b.s); break;
|
break;
|
||||||
case VAL_FUNCTION: neq = (a.fn != b.fn); break;
|
case VAL_BOOL:
|
||||||
case VAL_NIL: neq = 0; break;
|
neq = ((a.i != 0) != (b.i != 0));
|
||||||
default: neq = 1; break;
|
break;
|
||||||
|
case VAL_STRING:
|
||||||
|
neq = (a.s && b.s) ? (strcmp(a.s, b.s) != 0) : (a.s != b.s);
|
||||||
|
break;
|
||||||
|
case VAL_FUNCTION:
|
||||||
|
neq = (a.fn != b.fn);
|
||||||
|
break;
|
||||||
|
case VAL_NIL:
|
||||||
|
neq = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
neq = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* interop: bool vs int (0/1) */
|
/* interop: bool vs int (0/1) */
|
||||||
|
|
@ -55,6 +67,7 @@ case OP_NEQ: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
push_value(vm, make_bool(neq));
|
push_value(vm, make_bool(neq));
|
||||||
free_value(a); free_value(b);
|
free_value(a);
|
||||||
|
free_value(b);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,13 @@
|
||||||
case OP_HAS_KEY: {
|
case OP_HAS_KEY: {
|
||||||
Value key = pop_value(vm);
|
Value key = pop_value(vm);
|
||||||
Value m = pop_value(vm);
|
Value m = pop_value(vm);
|
||||||
if (m.type != VAL_MAP || key.type != VAL_STRING) { fprintf(stderr, "HAS_KEY expects (map, string)\n"); exit(1); }
|
if (m.type != VAL_MAP || key.type != VAL_STRING) {
|
||||||
|
fprintf(stderr, "HAS_KEY expects (map, string)\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
int ok = map_has(&m, key.s ? key.s : "");
|
int ok = map_has(&m, key.s ? key.s : "");
|
||||||
free_value(m); free_value(key);
|
free_value(m);
|
||||||
|
free_value(key);
|
||||||
push_value(vm, make_int(ok ? 1 : 0));
|
push_value(vm, make_int(ok ? 1 : 0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,10 @@
|
||||||
|
|
||||||
case OP_KEYS: {
|
case OP_KEYS: {
|
||||||
Value m = pop_value(vm);
|
Value m = pop_value(vm);
|
||||||
if (m.type != VAL_MAP) { fprintf(stderr, "KEYS expects map\n"); exit(1); }
|
if (m.type != VAL_MAP) {
|
||||||
|
fprintf(stderr, "KEYS expects map\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
Value arr = map_keys_array(&m);
|
Value arr = map_keys_array(&m);
|
||||||
free_value(m);
|
free_value(m);
|
||||||
push_value(vm, arr);
|
push_value(vm, arr);
|
||||||
|
|
|
||||||
|
|
@ -33,17 +33,23 @@
|
||||||
* @date 2025-10-16
|
* @date 2025-10-16
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
case OP_MAKE_MAP: {
|
case OP_MAKE_MAP: {
|
||||||
int pairs = inst.operand;
|
int pairs = inst.operand;
|
||||||
if (pairs < 0) { fprintf(stderr, "MAKE_MAP invalid pair count\n"); exit(1); }
|
if (pairs < 0) {
|
||||||
|
fprintf(stderr, "MAKE_MAP invalid pair count\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
Value m = make_map_empty();
|
Value m = make_map_empty();
|
||||||
for (int i = 0; i < pairs; ++i) {
|
for (int i = 0; i < pairs; ++i) {
|
||||||
Value val = pop_value(vm);
|
Value val = pop_value(vm);
|
||||||
Value key = pop_value(vm);
|
Value key = pop_value(vm);
|
||||||
if (key.type != VAL_STRING) { fprintf(stderr, "Map literal keys must be strings\n"); exit(1); }
|
if (key.type != VAL_STRING) {
|
||||||
|
fprintf(stderr, "Map literal keys must be strings\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
if (!map_set(&m, key.s ? key.s : "", val)) {
|
if (!map_set(&m, key.s ? key.s : "", val)) {
|
||||||
fprintf(stderr, "Map literal set failed\n"); exit(1);
|
fprintf(stderr, "Map literal set failed\n");
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
free_value(key);
|
free_value(key);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,10 @@
|
||||||
|
|
||||||
case OP_VALUES: {
|
case OP_VALUES: {
|
||||||
Value m = pop_value(vm);
|
Value m = pop_value(vm);
|
||||||
if (m.type != VAL_MAP) { fprintf(stderr, "VALUES expects map\n"); exit(1); }
|
if (m.type != VAL_MAP) {
|
||||||
|
fprintf(stderr, "VALUES expects map\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
Value arr = map_values_array(&m);
|
Value arr = map_values_array(&m);
|
||||||
free_value(m);
|
free_value(m);
|
||||||
push_value(vm, arr);
|
push_value(vm, arr);
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,10 @@
|
||||||
|
|
||||||
case OP_ABS: {
|
case OP_ABS: {
|
||||||
Value x = pop_value(vm);
|
Value x = pop_value(vm);
|
||||||
if (x.type != VAL_INT) { fprintf(stderr, "ABS expects int\n"); exit(1); }
|
if (x.type != VAL_INT) {
|
||||||
|
fprintf(stderr, "ABS expects int\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
int64_t v = x.i;
|
int64_t v = x.i;
|
||||||
if (v < 0) v = -v;
|
if (v < 0) v = -v;
|
||||||
push_value(vm, make_int(v));
|
push_value(vm, make_int(v));
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,15 @@ case OP_FMAX: {
|
||||||
Value out;
|
Value out;
|
||||||
if (!isnan(r) && !isinf(r) && r >= (double)INT64_MIN && r <= (double)INT64_MAX) {
|
if (!isnan(r) && !isinf(r) && r >= (double)INT64_MIN && r <= (double)INT64_MAX) {
|
||||||
int64_t ii = (int64_t)r;
|
int64_t ii = (int64_t)r;
|
||||||
if ((double)ii == r) out = make_int(ii); else out = make_float(r);
|
if ((double)ii == r)
|
||||||
|
out = make_int(ii);
|
||||||
|
else
|
||||||
|
out = make_float(r);
|
||||||
} else {
|
} else {
|
||||||
out = make_float(r);
|
out = make_float(r);
|
||||||
}
|
}
|
||||||
free_value(a); free_value(b);
|
free_value(a);
|
||||||
|
free_value(b);
|
||||||
push_value(vm, out);
|
push_value(vm, out);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,15 @@ case OP_FMIN: {
|
||||||
Value out;
|
Value out;
|
||||||
if (!isnan(r) && !isinf(r) && r >= (double)INT64_MIN && r <= (double)INT64_MAX) {
|
if (!isnan(r) && !isinf(r) && r >= (double)INT64_MIN && r <= (double)INT64_MAX) {
|
||||||
int64_t ii = (int64_t)r;
|
int64_t ii = (int64_t)r;
|
||||||
if ((double)ii == r) out = make_int(ii); else out = make_float(r);
|
if ((double)ii == r)
|
||||||
|
out = make_int(ii);
|
||||||
|
else
|
||||||
|
out = make_float(r);
|
||||||
} else {
|
} else {
|
||||||
out = make_float(r);
|
out = make_float(r);
|
||||||
}
|
}
|
||||||
free_value(a); free_value(b);
|
free_value(a);
|
||||||
|
free_value(b);
|
||||||
push_value(vm, out);
|
push_value(vm, out);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,14 @@ case OP_GCD: {
|
||||||
}
|
}
|
||||||
int64_t a = (va.type == VAL_INT) ? va.i : (int64_t)va.d;
|
int64_t a = (va.type == VAL_INT) ? va.i : (int64_t)va.d;
|
||||||
int64_t b = (vb.type == VAL_INT) ? vb.i : (int64_t)vb.d;
|
int64_t b = (vb.type == VAL_INT) ? vb.i : (int64_t)vb.d;
|
||||||
if (a == INT64_MIN) a = (int64_t)INT64_MAX; else if (a < 0) a = -a;
|
if (a == INT64_MIN)
|
||||||
if (b == INT64_MIN) b = (int64_t)INT64_MAX; else if (b < 0) b = -b;
|
a = (int64_t)INT64_MAX;
|
||||||
|
else if (a < 0)
|
||||||
|
a = -a;
|
||||||
|
if (b == INT64_MIN)
|
||||||
|
b = (int64_t)INT64_MAX;
|
||||||
|
else if (b < 0)
|
||||||
|
b = -b;
|
||||||
while (b != 0) {
|
while (b != 0) {
|
||||||
int64_t t = a % b;
|
int64_t t = a % b;
|
||||||
a = b;
|
a = b;
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,8 @@ case OP_ISQRT: {
|
||||||
uint64_t n = (uint64_t)a;
|
uint64_t n = (uint64_t)a;
|
||||||
uint64_t x = 0;
|
uint64_t x = 0;
|
||||||
uint64_t bit = (uint64_t)1 << 62; /* highest even bit set */
|
uint64_t bit = (uint64_t)1 << 62; /* highest even bit set */
|
||||||
while (bit > n) bit >>= 2;
|
while (bit > n)
|
||||||
|
bit >>= 2;
|
||||||
while (bit != 0) {
|
while (bit != 0) {
|
||||||
if (n >= x + bit) {
|
if (n >= x + bit) {
|
||||||
n -= x + bit;
|
n -= x + bit;
|
||||||
|
|
|
||||||
|
|
@ -25,17 +25,26 @@ case OP_LCM: {
|
||||||
}
|
}
|
||||||
int64_t a = (va.type == VAL_INT) ? va.i : (int64_t)va.d;
|
int64_t a = (va.type == VAL_INT) ? va.i : (int64_t)va.d;
|
||||||
int64_t b = (vb.type == VAL_INT) ? vb.i : (int64_t)vb.d;
|
int64_t b = (vb.type == VAL_INT) ? vb.i : (int64_t)vb.d;
|
||||||
if (a == INT64_MIN) a = (int64_t)INT64_MAX; else if (a < 0) a = -a;
|
if (a == INT64_MIN)
|
||||||
if (b == INT64_MIN) b = (int64_t)INT64_MAX; else if (b < 0) b = -b;
|
a = (int64_t)INT64_MAX;
|
||||||
|
else if (a < 0)
|
||||||
|
a = -a;
|
||||||
|
if (b == INT64_MIN)
|
||||||
|
b = (int64_t)INT64_MAX;
|
||||||
|
else if (b < 0)
|
||||||
|
b = -b;
|
||||||
if (a == 0 || b == 0) {
|
if (a == 0 || b == 0) {
|
||||||
free_value(va); free_value(vb);
|
free_value(va);
|
||||||
|
free_value(vb);
|
||||||
push_value(vm, make_int(0));
|
push_value(vm, make_int(0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* gcd(a,b) */
|
/* gcd(a,b) */
|
||||||
int64_t x = a, y = b;
|
int64_t x = a, y = b;
|
||||||
while (y != 0) {
|
while (y != 0) {
|
||||||
int64_t t = x % y; x = y; y = t;
|
int64_t t = x % y;
|
||||||
|
x = y;
|
||||||
|
y = t;
|
||||||
}
|
}
|
||||||
int64_t g = x;
|
int64_t g = x;
|
||||||
/* lcm = (a/g)*b (attempt to reduce overflow) */
|
/* lcm = (a/g)*b (attempt to reduce overflow) */
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,12 @@
|
||||||
case OP_MAX: {
|
case OP_MAX: {
|
||||||
Value b = pop_value(vm);
|
Value b = pop_value(vm);
|
||||||
Value a = pop_value(vm);
|
Value a = pop_value(vm);
|
||||||
if (a.type != VAL_INT || b.type != VAL_INT) { fprintf(stderr, "MAX expects ints\n"); exit(1); }
|
if (a.type != VAL_INT || b.type != VAL_INT) {
|
||||||
|
fprintf(stderr, "MAX expects ints\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
push_value(vm, make_int(a.i > b.i ? a.i : b.i));
|
push_value(vm, make_int(a.i > b.i ? a.i : b.i));
|
||||||
free_value(a); free_value(b);
|
free_value(a);
|
||||||
|
free_value(b);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,12 @@
|
||||||
case OP_MIN: {
|
case OP_MIN: {
|
||||||
Value b = pop_value(vm);
|
Value b = pop_value(vm);
|
||||||
Value a = pop_value(vm);
|
Value a = pop_value(vm);
|
||||||
if (a.type != VAL_INT || b.type != VAL_INT) { fprintf(stderr, "MIN expects ints\n"); exit(1); }
|
if (a.type != VAL_INT || b.type != VAL_INT) {
|
||||||
|
fprintf(stderr, "MIN expects ints\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
push_value(vm, make_int(a.i < b.i ? a.i : b.i));
|
push_value(vm, make_int(a.i < b.i ? a.i : b.i));
|
||||||
free_value(a); free_value(b);
|
free_value(a);
|
||||||
|
free_value(b);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,11 +34,16 @@
|
||||||
case OP_POW: {
|
case OP_POW: {
|
||||||
Value b = pop_value(vm);
|
Value b = pop_value(vm);
|
||||||
Value a = pop_value(vm);
|
Value a = pop_value(vm);
|
||||||
if (a.type != VAL_INT || b.type != VAL_INT) { fprintf(stderr, "POW expects ints\n"); exit(1); }
|
if (a.type != VAL_INT || b.type != VAL_INT) {
|
||||||
|
fprintf(stderr, "POW expects ints\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
int64_t base = a.i;
|
int64_t base = a.i;
|
||||||
int64_t exp = b.i;
|
int64_t exp = b.i;
|
||||||
int64_t res = 1;
|
int64_t res = 1;
|
||||||
if (exp < 0) { res = 0; } else {
|
if (exp < 0) {
|
||||||
|
res = 0;
|
||||||
|
} else {
|
||||||
while (exp > 0) {
|
while (exp > 0) {
|
||||||
if (exp & 1) res *= base;
|
if (exp & 1) res *= base;
|
||||||
base *= base;
|
base *= base;
|
||||||
|
|
@ -46,6 +51,7 @@ case OP_POW: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
push_value(vm, make_int(res));
|
push_value(vm, make_int(res));
|
||||||
free_value(a); free_value(b);
|
free_value(a);
|
||||||
|
free_value(b);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,12 +36,21 @@
|
||||||
case OP_RANDOM_INT: {
|
case OP_RANDOM_INT: {
|
||||||
Value hi = pop_value(vm);
|
Value hi = pop_value(vm);
|
||||||
Value lo = pop_value(vm);
|
Value lo = pop_value(vm);
|
||||||
if (lo.type != VAL_INT || hi.type != VAL_INT) { fprintf(stderr, "RANDOM_INT expects (int, int)\n"); exit(1); }
|
if (lo.type != VAL_INT || hi.type != VAL_INT) {
|
||||||
|
fprintf(stderr, "RANDOM_INT expects (int, int)\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
int64_t a = lo.i, b = hi.i;
|
int64_t a = lo.i, b = hi.i;
|
||||||
if (b <= a) { push_value(vm, make_int((int64_t)a)); free_value(lo); free_value(hi); break; }
|
if (b <= a) {
|
||||||
|
push_value(vm, make_int((int64_t)a));
|
||||||
|
free_value(lo);
|
||||||
|
free_value(hi);
|
||||||
|
break;
|
||||||
|
}
|
||||||
int64_t span = b - a;
|
int64_t span = b - a;
|
||||||
int64_t r = (int64_t)(rand() % (span));
|
int64_t r = (int64_t)(rand() % (span));
|
||||||
push_value(vm, make_int(a + r));
|
push_value(vm, make_int(a + r));
|
||||||
free_value(lo); free_value(hi);
|
free_value(lo);
|
||||||
|
free_value(hi);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,10 @@
|
||||||
|
|
||||||
case OP_RANDOM_SEED: {
|
case OP_RANDOM_SEED: {
|
||||||
Value seed = pop_value(vm);
|
Value seed = pop_value(vm);
|
||||||
if (seed.type != VAL_INT) { fprintf(stderr, "RANDOM_SEED expects int\n"); exit(1); }
|
if (seed.type != VAL_INT) {
|
||||||
|
fprintf(stderr, "RANDOM_SEED expects int\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
srand((unsigned int)seed.i);
|
srand((unsigned int)seed.i);
|
||||||
free_value(seed);
|
free_value(seed);
|
||||||
push_value(vm, make_int(0));
|
push_value(vm, make_int(0));
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,12 @@ case OP_SIGN: {
|
||||||
if (v.type == VAL_INT) {
|
if (v.type == VAL_INT) {
|
||||||
out = (v.i > 0) - (v.i < 0);
|
out = (v.i > 0) - (v.i < 0);
|
||||||
} else if (v.type == VAL_FLOAT) {
|
} else if (v.type == VAL_FLOAT) {
|
||||||
if (v.d > 0.0) out = 1;
|
if (v.d > 0.0)
|
||||||
else if (v.d < 0.0) out = -1;
|
out = 1;
|
||||||
else out = 0;
|
else if (v.d < 0.0)
|
||||||
|
out = -1;
|
||||||
|
else
|
||||||
|
out = 0;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Runtime type error: SIGN expects number, got %s\n", value_type_name(v.type));
|
fprintf(stderr, "Runtime type error: SIGN expects number, got %s\n", value_type_name(v.type));
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ case OP_NC_CLEAR: {
|
||||||
push_value(vm, make_int(-1));
|
push_value(vm, make_int(-1));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
(void)_fun_nc; (void)_fun_nc_std;
|
(void)_fun_nc;
|
||||||
|
(void)_fun_nc_std;
|
||||||
push_value(vm, make_int(-1));
|
push_value(vm, make_int(-1));
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,8 @@ case OP_NC_DRAW_TEXT: {
|
||||||
push_value(vm, make_int(-1));
|
push_value(vm, make_int(-1));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
(void)_fun_nc; (void)_fun_nc_std;
|
(void)_fun_nc;
|
||||||
|
(void)_fun_nc_std;
|
||||||
if (text) free(text);
|
if (text) free(text);
|
||||||
push_value(vm, make_int(-1));
|
push_value(vm, make_int(-1));
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,9 @@ case OP_NC_GETCH: {
|
||||||
push_value(vm, make_int(-1));
|
push_value(vm, make_int(-1));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
(void)_fun_nc; (void)_fun_nc_std; (void)timeout_ms;
|
(void)_fun_nc;
|
||||||
|
(void)_fun_nc_std;
|
||||||
|
(void)timeout_ms;
|
||||||
push_value(vm, make_int(-1));
|
push_value(vm, make_int(-1));
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,21 @@
|
||||||
/* NC_INIT */
|
/* NC_INIT */
|
||||||
case OP_NC_INIT: {
|
case OP_NC_INIT: {
|
||||||
#ifdef FUN_WITH_NOTCURSES
|
#ifdef FUN_WITH_NOTCURSES
|
||||||
if (_fun_nc) { push_value(vm, make_int(1)); break; }
|
if (_fun_nc) {
|
||||||
|
push_value(vm, make_int(1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
struct notcurses_options opts = {0};
|
struct notcurses_options opts = {0};
|
||||||
_fun_nc = notcurses_core_init(&opts, NULL);
|
_fun_nc = notcurses_core_init(&opts, NULL);
|
||||||
if (!_fun_nc) { push_value(vm, make_int(0)); break; }
|
if (!_fun_nc) {
|
||||||
|
push_value(vm, make_int(0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
_fun_nc_std = notcurses_stdplane(_fun_nc);
|
_fun_nc_std = notcurses_stdplane(_fun_nc);
|
||||||
push_value(vm, make_int(1));
|
push_value(vm, make_int(1));
|
||||||
#else
|
#else
|
||||||
(void)_fun_nc; (void)_fun_nc_std;
|
(void)_fun_nc;
|
||||||
|
(void)_fun_nc_std;
|
||||||
fprintf(stderr, "Notcurses support disabled at build time. Reconfigure with -DFUN_WITH_NOTCURSES=ON.\n");
|
fprintf(stderr, "Notcurses support disabled at build time. Reconfigure with -DFUN_WITH_NOTCURSES=ON.\n");
|
||||||
push_value(vm, make_int(0));
|
push_value(vm, make_int(0));
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ case OP_NC_SHUTDOWN: {
|
||||||
_fun_nc_std = NULL;
|
_fun_nc_std = NULL;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
(void)_fun_nc; (void)_fun_nc_std;
|
(void)_fun_nc;
|
||||||
|
(void)_fun_nc_std;
|
||||||
#endif
|
#endif
|
||||||
push_value(vm, make_int(0));
|
push_value(vm, make_int(0));
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,16 @@ case OP_OPENSSL_MD5: {
|
||||||
Value vdata = pop_value(vm);
|
Value vdata = pop_value(vm);
|
||||||
char *s = value_to_string_alloc(&vdata);
|
char *s = value_to_string_alloc(&vdata);
|
||||||
free_value(vdata);
|
free_value(vdata);
|
||||||
if (!s) { push_value(vm, make_string("")); break; }
|
if (!s) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
char *hex = fun_openssl_md5_hex((const unsigned char *)s, strlen(s));
|
char *hex = fun_openssl_md5_hex((const unsigned char *)s, strlen(s));
|
||||||
free(s);
|
free(s);
|
||||||
if (!hex) { push_value(vm, make_string("")); break; }
|
if (!hex) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
Value out = make_string(hex);
|
Value out = make_string(hex);
|
||||||
free(hex);
|
free(hex);
|
||||||
push_value(vm, out);
|
push_value(vm, out);
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,16 @@ case OP_OPENSSL_RIPEMD160: {
|
||||||
Value vdata = pop_value(vm);
|
Value vdata = pop_value(vm);
|
||||||
char *s = value_to_string_alloc(&vdata);
|
char *s = value_to_string_alloc(&vdata);
|
||||||
free_value(vdata);
|
free_value(vdata);
|
||||||
if (!s) { push_value(vm, make_string("")); break; }
|
if (!s) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
char *hex = fun_openssl_ripemd160_hex((const unsigned char *)s, strlen(s));
|
char *hex = fun_openssl_ripemd160_hex((const unsigned char *)s, strlen(s));
|
||||||
free(s);
|
free(s);
|
||||||
if (!hex) { push_value(vm, make_string("")); break; }
|
if (!hex) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
Value out = make_string(hex);
|
Value out = make_string(hex);
|
||||||
free(hex);
|
free(hex);
|
||||||
push_value(vm, out);
|
push_value(vm, out);
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,16 @@ case OP_OPENSSL_SHA256: {
|
||||||
Value vdata = pop_value(vm);
|
Value vdata = pop_value(vm);
|
||||||
char *s = value_to_string_alloc(&vdata);
|
char *s = value_to_string_alloc(&vdata);
|
||||||
free_value(vdata);
|
free_value(vdata);
|
||||||
if (!s) { push_value(vm, make_string("")); break; }
|
if (!s) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
char *hex = fun_openssl_sha256_hex((const unsigned char *)s, strlen(s));
|
char *hex = fun_openssl_sha256_hex((const unsigned char *)s, strlen(s));
|
||||||
free(s);
|
free(s);
|
||||||
if (!hex) { push_value(vm, make_string("")); break; }
|
if (!hex) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
Value out = make_string(hex);
|
Value out = make_string(hex);
|
||||||
free(hex);
|
free(hex);
|
||||||
push_value(vm, out);
|
push_value(vm, out);
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,16 @@ case OP_OPENSSL_SHA512: {
|
||||||
Value vdata = pop_value(vm);
|
Value vdata = pop_value(vm);
|
||||||
char *s = value_to_string_alloc(&vdata);
|
char *s = value_to_string_alloc(&vdata);
|
||||||
free_value(vdata);
|
free_value(vdata);
|
||||||
if (!s) { push_value(vm, make_string("")); break; }
|
if (!s) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
char *hex = fun_openssl_sha512_hex((const unsigned char *)s, strlen(s));
|
char *hex = fun_openssl_sha512_hex((const unsigned char *)s, strlen(s));
|
||||||
free(s);
|
free(s);
|
||||||
if (!hex) { push_value(vm, make_string("")); break; }
|
if (!hex) {
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
Value out = make_string(hex);
|
Value out = make_string(hex);
|
||||||
free(hex);
|
free(hex);
|
||||||
push_value(vm, out);
|
push_value(vm, out);
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@
|
||||||
* Stack after: [int ms]
|
* Stack after: [int ms]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
case OP_CLOCK_MONO_MS: {
|
case OP_CLOCK_MONO_MS: {
|
||||||
int64_t ms;
|
int64_t ms;
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,9 @@
|
||||||
* - If types are wrong, prints error and pushes empty string to keep stack safe.
|
* - If types are wrong, prints error and pushes empty string to keep stack safe.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
case OP_DATE_FORMAT: {
|
case OP_DATE_FORMAT: {
|
||||||
Value fmt = pop_value(vm);
|
Value fmt = pop_value(vm);
|
||||||
|
|
@ -42,7 +42,8 @@ case OP_DATE_FORMAT: {
|
||||||
#else
|
#else
|
||||||
struct tm *ptm = localtime(&secs);
|
struct tm *ptm = localtime(&secs);
|
||||||
if (!ptm) {
|
if (!ptm) {
|
||||||
free_value(ms); free_value(fmt);
|
free_value(ms);
|
||||||
|
free_value(fmt);
|
||||||
push_value(vm, make_string(""));
|
push_value(vm, make_string(""));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,10 @@ case OP_PROC_RUN: {
|
||||||
out[len] = '\0';
|
out[len] = '\0';
|
||||||
int status = pclose(fp);
|
int status = pclose(fp);
|
||||||
#ifdef __unix__
|
#ifdef __unix__
|
||||||
if (WIFEXITED(status)) exit_code = WEXITSTATUS(status);
|
if (WIFEXITED(status))
|
||||||
else exit_code = -1;
|
exit_code = WEXITSTATUS(status);
|
||||||
|
else
|
||||||
|
exit_code = -1;
|
||||||
#else
|
#else
|
||||||
exit_code = status;
|
exit_code = status;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,12 @@ case OP_PROC_SYSTEM: {
|
||||||
int status = system(cmd);
|
int status = system(cmd);
|
||||||
int code = -1;
|
int code = -1;
|
||||||
#ifdef __unix__
|
#ifdef __unix__
|
||||||
if (status == -1) code = -1;
|
if (status == -1)
|
||||||
else if (WIFEXITED(status)) code = WEXITSTATUS(status);
|
code = -1;
|
||||||
else code = -1;
|
else if (WIFEXITED(status))
|
||||||
|
code = WEXITSTATUS(status);
|
||||||
|
else
|
||||||
|
code = -1;
|
||||||
#else
|
#else
|
||||||
code = status;
|
code = status;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@
|
||||||
|
|
||||||
/* Platform-specific headers guarded per OS to avoid leaking problematic macros */
|
/* Platform-specific headers guarded per OS to avoid leaking problematic macros */
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
#include <windows.h>
|
|
||||||
#include <bcrypt.h>
|
#include <bcrypt.h>
|
||||||
|
#include <windows.h>
|
||||||
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
|
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/random.h>
|
#include <sys/random.h>
|
||||||
|
|
@ -105,8 +105,10 @@ case OP_RANDOM_NUMBER: {
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
int fd = open("/dev/urandom", O_RDONLY);
|
int fd = open("/dev/urandom", O_RDONLY);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
size_t off = 0; ssize_t n;
|
size_t off = 0;
|
||||||
while (off < (size_t)len && (n = read(fd, raw + off, (size_t)len - off)) > 0) off += (size_t)n;
|
ssize_t n;
|
||||||
|
while (off < (size_t)len && (n = read(fd, raw + off, (size_t)len - off)) > 0)
|
||||||
|
off += (size_t)n;
|
||||||
close(fd);
|
close(fd);
|
||||||
ok = (off == (size_t)len);
|
ok = (off == (size_t)len);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,10 +37,19 @@ case OP_SERIAL_CONFIG: {
|
||||||
// Data bits
|
// Data bits
|
||||||
options.c_cflag &= ~CSIZE;
|
options.c_cflag &= ~CSIZE;
|
||||||
switch (data_bits) {
|
switch (data_bits) {
|
||||||
case 5: options.c_cflag |= CS5; break;
|
case 5:
|
||||||
case 6: options.c_cflag |= CS6; break;
|
options.c_cflag |= CS5;
|
||||||
case 7: options.c_cflag |= CS7; break;
|
break;
|
||||||
case 8: default: options.c_cflag |= CS8; break;
|
case 6:
|
||||||
|
options.c_cflag |= CS6;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
options.c_cflag |= CS7;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
default:
|
||||||
|
options.c_cflag |= CS8;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parity
|
// Parity
|
||||||
|
|
|
||||||
|
|
@ -94,25 +94,63 @@ case OP_SERIAL_OPEN: {
|
||||||
speed_t speed;
|
speed_t speed;
|
||||||
|
|
||||||
switch (baud) {
|
switch (baud) {
|
||||||
case 50: speed = B50; break;
|
case 50:
|
||||||
case 75: speed = B75; break;
|
speed = B50;
|
||||||
case 110: speed = B110; break;
|
break;
|
||||||
case 134: speed = B134; break;
|
case 75:
|
||||||
case 150: speed = B150; break;
|
speed = B75;
|
||||||
case 200: speed = B200; break;
|
break;
|
||||||
case 300: speed = B300; break;
|
case 110:
|
||||||
case 600: speed = B600; break;
|
speed = B110;
|
||||||
case 1200: speed = B1200; break;
|
break;
|
||||||
case 1800: speed = B1800; break;
|
case 134:
|
||||||
case 2400: speed = B2400; break;
|
speed = B134;
|
||||||
case 4800: speed = B4800; break;
|
break;
|
||||||
case 9600: speed = B9600; break;
|
case 150:
|
||||||
case 19200: speed = B19200; break;
|
speed = B150;
|
||||||
case 38400: speed = B38400; break;
|
break;
|
||||||
case 57600: speed = B57600; break;
|
case 200:
|
||||||
case 115200: speed = B115200; break;
|
speed = B200;
|
||||||
case 230400: speed = B230400; break;
|
break;
|
||||||
default: speed = B9600; break;
|
case 300:
|
||||||
|
speed = B300;
|
||||||
|
break;
|
||||||
|
case 600:
|
||||||
|
speed = B600;
|
||||||
|
break;
|
||||||
|
case 1200:
|
||||||
|
speed = B1200;
|
||||||
|
break;
|
||||||
|
case 1800:
|
||||||
|
speed = B1800;
|
||||||
|
break;
|
||||||
|
case 2400:
|
||||||
|
speed = B2400;
|
||||||
|
break;
|
||||||
|
case 4800:
|
||||||
|
speed = B4800;
|
||||||
|
break;
|
||||||
|
case 9600:
|
||||||
|
speed = B9600;
|
||||||
|
break;
|
||||||
|
case 19200:
|
||||||
|
speed = B19200;
|
||||||
|
break;
|
||||||
|
case 38400:
|
||||||
|
speed = B38400;
|
||||||
|
break;
|
||||||
|
case 57600:
|
||||||
|
speed = B57600;
|
||||||
|
break;
|
||||||
|
case 115200:
|
||||||
|
speed = B115200;
|
||||||
|
break;
|
||||||
|
case 230400:
|
||||||
|
speed = B230400;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
speed = B9600;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = open(path, O_RDWR | O_NOCTTY | O_NDELAY);
|
fd = open(path, O_RDWR | O_NOCTTY | O_NDELAY);
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,8 @@ case OP_SOCK_RECV: {
|
||||||
if (out) {
|
if (out) {
|
||||||
ssize_t n = recv(fd, out, (size_t)maxlen, 0);
|
ssize_t n = recv(fd, out, (size_t)maxlen, 0);
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
free(out); out = NULL;
|
free(out);
|
||||||
|
out = NULL;
|
||||||
} else {
|
} else {
|
||||||
out[n] = '\0';
|
out[n] = '\0';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,10 @@ case OP_SOCK_SEND: {
|
||||||
const char *buf = datav.s ? datav.s : "";
|
const char *buf = datav.s ? datav.s : "";
|
||||||
size_t len = strlen(buf);
|
size_t len = strlen(buf);
|
||||||
ssize_t n = send(fd, buf, len, 0);
|
ssize_t n = send(fd, buf, len, 0);
|
||||||
if (n >= 0) sent = (int)n; else sent = -1;
|
if (n >= 0)
|
||||||
|
sent = (int)n;
|
||||||
|
else
|
||||||
|
sent = -1;
|
||||||
#endif
|
#endif
|
||||||
free_value(datav);
|
free_value(datav);
|
||||||
free_value(fdv);
|
free_value(fdv);
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,10 @@ case OP_SOCK_TCP_CONNECT: {
|
||||||
for (rp = res; rp != NULL; rp = rp->ai_next) {
|
for (rp = res; rp != NULL; rp = rp->ai_next) {
|
||||||
int s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
int s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||||
if (s < 0) continue;
|
if (s < 0) continue;
|
||||||
if (connect(s, rp->ai_addr, rp->ai_addrlen) == 0) { fd = s; break; }
|
if (connect(s, rp->ai_addr, rp->ai_addrlen) == 0) {
|
||||||
|
fd = s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
close(s);
|
close(s);
|
||||||
}
|
}
|
||||||
if (res) freeaddrinfo(res);
|
if (res) freeaddrinfo(res);
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#ifdef __unix__
|
#ifdef __unix__
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -60,12 +60,21 @@ static void fun_thr_lock_init(void) {
|
||||||
g_thr_lock_inited = 1;
|
g_thr_lock_inited = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void fun_lock(void) { if (!g_thr_lock_inited) fun_thr_lock_init(); EnterCriticalSection(&g_thr_lock); }
|
static void fun_lock(void) {
|
||||||
static void fun_unlock(void) { LeaveCriticalSection(&g_thr_lock); }
|
if (!g_thr_lock_inited) fun_thr_lock_init();
|
||||||
|
EnterCriticalSection(&g_thr_lock);
|
||||||
|
}
|
||||||
|
static void fun_unlock(void) {
|
||||||
|
LeaveCriticalSection(&g_thr_lock);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
static pthread_mutex_t g_thr_lock = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t g_thr_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
static void fun_lock(void) { pthread_mutex_lock(&g_thr_lock); }
|
static void fun_lock(void) {
|
||||||
static void fun_unlock(void) { pthread_mutex_unlock(&g_thr_lock); }
|
pthread_mutex_lock(&g_thr_lock);
|
||||||
|
}
|
||||||
|
static void fun_unlock(void) {
|
||||||
|
pthread_mutex_unlock(&g_thr_lock);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -130,7 +139,13 @@ static int fun_alloc_thread_slot(void) {
|
||||||
fun_lock();
|
fun_lock();
|
||||||
int idx = -1;
|
int idx = -1;
|
||||||
for (int i = 0; i < FUN_MAX_THREADS; ++i) {
|
for (int i = 0; i < FUN_MAX_THREADS; ++i) {
|
||||||
if (!g_threads[i].used) { g_threads[i].used = 1; g_threads[i].done = 0; g_threads[i].result = make_nil(); idx = i; break; }
|
if (!g_threads[i].used) {
|
||||||
|
g_threads[i].used = 1;
|
||||||
|
g_threads[i].done = 0;
|
||||||
|
g_threads[i].result = make_nil();
|
||||||
|
idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fun_unlock();
|
fun_unlock();
|
||||||
return idx;
|
return idx;
|
||||||
|
|
@ -176,16 +191,20 @@ static int fun_thread_spawn(Value fnVal, Value argsMaybe, int hasArgs) {
|
||||||
if (slot < 0) {
|
if (slot < 0) {
|
||||||
fprintf(stderr, "Runtime error: too many threads\n");
|
fprintf(stderr, "Runtime error: too many threads\n");
|
||||||
/* free args */
|
/* free args */
|
||||||
for (int i = 0; i < argc; ++i) free_value(args[i]);
|
for (int i = 0; i < argc; ++i)
|
||||||
|
free_value(args[i]);
|
||||||
free(args);
|
free(args);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FunTask *task = (FunTask *)calloc(1, sizeof(FunTask));
|
FunTask *task = (FunTask *)calloc(1, sizeof(FunTask));
|
||||||
if (!task) {
|
if (!task) {
|
||||||
for (int i = 0; i < argc; ++i) free_value(args[i]);
|
for (int i = 0; i < argc; ++i)
|
||||||
|
free_value(args[i]);
|
||||||
free(args);
|
free(args);
|
||||||
fun_lock(); g_threads[slot].used = 0; fun_unlock();
|
fun_lock();
|
||||||
|
g_threads[slot].used = 0;
|
||||||
|
fun_unlock();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
task->fn = fnVal.fn;
|
task->fn = fnVal.fn;
|
||||||
|
|
@ -197,25 +216,35 @@ static int fun_thread_spawn(Value fnVal, Value argsMaybe, int hasArgs) {
|
||||||
HANDLE h = CreateThread(NULL, 0, fun_thread_main, (LPVOID)task, 0, &g_threads[slot].threadId);
|
HANDLE h = CreateThread(NULL, 0, fun_thread_main, (LPVOID)task, 0, &g_threads[slot].threadId);
|
||||||
if (!h) {
|
if (!h) {
|
||||||
fprintf(stderr, "Runtime error: CreateThread failed\n");
|
fprintf(stderr, "Runtime error: CreateThread failed\n");
|
||||||
for (int i = 0; i < argc; ++i) free_value(args[i]);
|
for (int i = 0; i < argc; ++i)
|
||||||
|
free_value(args[i]);
|
||||||
free(args);
|
free(args);
|
||||||
free(task);
|
free(task);
|
||||||
fun_lock(); g_threads[slot].used = 0; fun_unlock();
|
fun_lock();
|
||||||
|
g_threads[slot].used = 0;
|
||||||
|
fun_unlock();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
fun_lock(); g_threads[slot].handle = h; fun_unlock();
|
fun_lock();
|
||||||
|
g_threads[slot].handle = h;
|
||||||
|
fun_unlock();
|
||||||
#else
|
#else
|
||||||
pthread_t tid;
|
pthread_t tid;
|
||||||
int rc = pthread_create(&tid, NULL, fun_thread_main, (void *)task);
|
int rc = pthread_create(&tid, NULL, fun_thread_main, (void *)task);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
fprintf(stderr, "Runtime error: pthread_create failed\n");
|
fprintf(stderr, "Runtime error: pthread_create failed\n");
|
||||||
for (int i = 0; i < argc; ++i) free_value(args[i]);
|
for (int i = 0; i < argc; ++i)
|
||||||
|
free_value(args[i]);
|
||||||
free(args);
|
free(args);
|
||||||
free(task);
|
free(task);
|
||||||
fun_lock(); g_threads[slot].used = 0; fun_unlock();
|
fun_lock();
|
||||||
|
g_threads[slot].used = 0;
|
||||||
|
fun_unlock();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
fun_lock(); g_threads[slot].handle = tid; fun_unlock();
|
fun_lock();
|
||||||
|
g_threads[slot].handle = tid;
|
||||||
|
fun_unlock();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return slot + 1; /* external thread id: 1..N */
|
return slot + 1; /* external thread id: 1..N */
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue