More OpenSSL and documenation fun. No more words to say. (0.38.13)
This commit is contained in:
parent
53698478d9
commit
38968a9a51
33 changed files with 498 additions and 88 deletions
|
|
@ -1,5 +1,5 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
project(fun VERSION 0.38.12 LANGUAGES C)
|
||||
project(fun VERSION 0.38.13 LANGUAGES C)
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
|
|
|||
32
README.md
32
README.md
|
|
@ -87,16 +87,16 @@ See [./lib/](https://git.xw3.org/fun/fun/src/branch/main/lib) for what the stand
|
|||
### Optional extensions (build-time selectable / only testing this on Linux actually):
|
||||
|
||||
- [CGI](https://en.wikipedia.org/wiki/Common_Gateway_Interface) support builtin using [kcgi](https://kristaps.bsd.lv/kcgi/) (optional) ☐
|
||||
- [cURL](https://curl.se/) support builtin using [libcurl](https://curl.se/libcurl/) (optional) ☑
|
||||
- [INI](https://en.wikipedia.org/wiki/INI_file) support builtin using [iniparser](https://gitlab.com/iniparser/iniparser/) (optional) ☑
|
||||
- [JSON](https://www.json.org/) support builtin using [json-c](https://github.com/json-c/json-c) (optional) ☑
|
||||
- [libSQL](https://github.com/tursodatabase/libsql) support builtin as a compatible alternative to SQLite (optional) ☑
|
||||
- [PCRE2](https://pcre2project.github.io/pcre2/) support builtin for Perl-Compatible Regular Expressions (optional) ☑
|
||||
- [PCSC](https://pcscworkgroup.com/) smart card support builtin using [PCSC lite](https://pcsclite.apdu.fr/) (optional) ☑
|
||||
- [OpenSSL](https://www.openssl.org/) integration (currently MD5 helper) (optional) ☑
|
||||
- [SQLite](https://sqlite.org/) support builtin (optional) ☑
|
||||
- [Tk](https://www.tcl-lang.org/) support builtin for GUI application development (optional) ☑
|
||||
- [XML](https://www.w3.org/XML/) support builtin using [libxml2](https://gitlab.gnome.org/GNOME/libxml2/-/wikis/home) (optional) ☑
|
||||
- [cURL (libcurl)](./docs/external/curl.md) (optional) ☑
|
||||
- [INI (iniparser)](./docs/external/ini.md) (optional) ☑
|
||||
- [JSON (json-c)](./docs/external/json.md) (optional) ☑
|
||||
- [libSQL](./docs/external/libsql.md) (optional) ☑
|
||||
- [PCRE2](./docs/external/pcre2.md) (optional) ☑
|
||||
- [PCSC (smart cards)](./docs/external/pcsc.md) (optional) ☑
|
||||
- [OpenSSL](./docs/external/openssl.md) (optional) ☑
|
||||
- [SQLite](./docs/external/sqlite.md) (optional) ☑
|
||||
- [Tk (Tcl/Tk GUI)](./docs/external/tcltk.md) (optional) ☑
|
||||
- [XML (libxml2)](./docs/external/xml2.md) (optional) ☑
|
||||
|
||||
☑ = Done / ☐ = Planned or in progress.
|
||||
|
||||
|
|
@ -106,17 +106,7 @@ There are some libs written in Fun available in the [./lib/](https://git.xw3.org
|
|||
|
||||
### OpenSSL quickstart (MD5)
|
||||
|
||||
The OpenSSL integration is optional and currently provides an `openssl_md5(data)` helper.
|
||||
|
||||
- Build with OpenSSL enabled:
|
||||
- `cmake -S . -B build_debug -DFUN_WITH_OPENSSL=ON`
|
||||
- `cmake --build build_debug --target fun`
|
||||
- Run the example:
|
||||
- `./build_debug/fun examples/crypto/openssl_md5.fun`
|
||||
|
||||
If OpenSSL is disabled, the function returns an empty string (consistent with other optional extensions).
|
||||
|
||||
Note: On OpenSSL 3.x the legacy `MD5_*` APIs are deprecated; you may see warnings during build.
|
||||
See the dedicated page: ./docs/external/openssl.md
|
||||
|
||||
## Documentation
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,13 @@ This file serves as an index of the documents in this directory. Links are relat
|
|||
- [bytecode-format.md](./bytecode-format.md) - Reference for the bytecode format (split out from internals for convenience).
|
||||
- [roadmap.md](./roadmap.md) - High-level direction, planned features, and pointers to issues.
|
||||
|
||||
## External extensions
|
||||
|
||||
Documentation for optional, build-time selectable integrations lives in [external/](./external/):
|
||||
|
||||
- [Index of extensions](./external/README.md)
|
||||
- Highlights: [cURL](./external/curl.md), [INI](./external/ini.md), [JSON](./external/json.md), [XML (libxml2)](./external/xml2.md), [SQLite](./external/sqlite.md), [libSQL](./external/libsql.md), [PCRE2](./external/pcre2.md), [PC/SC](./external/pcsc.md), [Notcurses](./external/notcurses.md), [Tcl/Tk](./external/tcltk.md), [OpenSSL](./external/openssl.md)
|
||||
|
||||
## Tips
|
||||
|
||||
- When building from the repo without installing, set `FUN_LIB_DIR` to the local `./lib` directory so examples and the REPL can locate the stdlib.
|
||||
|
|
|
|||
|
|
@ -29,10 +29,10 @@ See also: [includes.md](./includes.md) for namespaced includes and search order.
|
|||
## Examples
|
||||
Run a script:
|
||||
```
|
||||
FUN_LIB_DIR=./lib ./build_debug/fun examples/hello.fun
|
||||
FUN_LIB_DIR=./lib ./build/fun examples/hello.fun
|
||||
```
|
||||
|
||||
Start the REPL:
|
||||
```
|
||||
./build_debug/fun -i
|
||||
./build/fun -i
|
||||
```
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ FUN_LIB_DIR="$(pwd)/lib" fun examples/crypto/openssl_md5.fun
|
|||
|
||||
Browse the `examples/` tree for areas of interest:
|
||||
|
||||
- crypto — crypto demonstrations (e.g., OpenSSL MD5 helper; requires build with `-DFUN_WITH_OPENSSL=ON`)
|
||||
- crypto — crypto demonstrations (e.g., OpenSSL MD5/SHA-256/SHA-512 helpers; requires build with `-DFUN_WITH_OPENSSL=ON`)
|
||||
- blocking / interactive — I/O or user-interactive patterns
|
||||
- error / broken — negative tests and error showcases
|
||||
- math — numeric operations
|
||||
|
|
|
|||
25
docs/external/README.md
vendored
Normal file
25
docs/external/README.md
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# External integrations (optional extensions)
|
||||
|
||||
This section documents Fun’s optional, build‑time selectable extensions. Each page covers:
|
||||
- How to enable the extension via CMake option (FUN_WITH_*)
|
||||
- Build requirements and detection notes
|
||||
- Available opcodes and/or helper functions
|
||||
- Minimal usage examples and links to example scripts
|
||||
|
||||
Extensions:
|
||||
|
||||
- [cURL (libcurl)](./curl.md)
|
||||
- [INI (iniparser)](./ini.md)
|
||||
- [JSON (json-c)](./json.md)
|
||||
- [libxml2 (XML)](./xml2.md)
|
||||
- [SQLite](./sqlite.md)
|
||||
- [libSQL (SQLite-compatible)](./libsql.md)
|
||||
- [PCRE2 (Perl-compatible regex)](./pcre2.md)
|
||||
- [PC/SC (Smart cards)](./pcsc.md)
|
||||
- [Notcurses (TUI)](./notcurses.md)
|
||||
- [Tcl/Tk (GUI)](./tcltk.md)
|
||||
- [OpenSSL (MD5 helper)](./openssl.md)
|
||||
|
||||
Notes:
|
||||
- These integrations are optional; the VM compiles without them.
|
||||
- When disabled, related builtins usually return empty strings/neutral values rather than fail hard, mirroring existing optionality patterns.
|
||||
14
docs/external/curl.md
vendored
Normal file
14
docs/external/curl.md
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# cURL (libcurl) extension (optional)
|
||||
|
||||
- CMake option: FUN_WITH_CURL=ON
|
||||
- Purpose: HTTP helpers using libcurl.
|
||||
- Homepage: https://curl.se/libcurl/
|
||||
|
||||
Opcodes:
|
||||
- OP_CURL_GET: GET; pops url:string; pushes body:string (empty on error/disabled)
|
||||
- OP_CURL_POST: POST; pops body:string, url:string; pushes response:string
|
||||
- OP_CURL_DOWNLOAD: Download to file; pops path:string, url:string; pushes 1/0
|
||||
|
||||
Notes:
|
||||
- Requires libcurl development headers/libs.
|
||||
- When disabled, helpers return empty strings/0 to match optional behavior.
|
||||
20
docs/external/ini.md
vendored
Normal file
20
docs/external/ini.md
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# INI (iniparser) extension (optional)
|
||||
|
||||
- CMake option: FUN_WITH_INI=ON
|
||||
- Purpose: Read/write simple INI configuration files.
|
||||
- Homepage: https://github.com/ndevilla/iniparser
|
||||
|
||||
Opcodes:
|
||||
- OP_INI_LOAD: pops path; pushes handle (>0) or 0
|
||||
- OP_INI_FREE: pops handle; pushes 1/0
|
||||
- OP_INI_GET_STRING: pops def, key, section, handle; pushes string
|
||||
- OP_INI_GET_INT: pops def, key, section, handle; pushes int
|
||||
- OP_INI_GET_DOUBLE: pops def, key, section, handle; pushes float
|
||||
- OP_INI_GET_BOOL: pops def, key, section, handle; pushes 0/1
|
||||
- OP_INI_SET: pops value, key, section, handle; pushes 1/0
|
||||
- OP_INI_UNSET: pops key, section, handle; pushes 1/0
|
||||
- OP_INI_SAVE: pops path, handle; pushes 1/0
|
||||
|
||||
Notes:
|
||||
- Requires iniparser development headers/libs.
|
||||
- When disabled, helpers return neutral values (0/empty strings) like other optional extensions.
|
||||
15
docs/external/json.md
vendored
Normal file
15
docs/external/json.md
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# JSON (json-c) extension (optional)
|
||||
|
||||
- CMake option: FUN_WITH_JSON=ON
|
||||
- Purpose: JSON parse/stringify and file helpers via json-c.
|
||||
- Homepage: https://json-c.github.io/json-c/
|
||||
|
||||
Opcodes:
|
||||
- OP_JSON_PARSE: pops text; pushes value or Nil on error
|
||||
- OP_JSON_STRINGIFY: pops pretty:int(0/1), value; pushes string
|
||||
- OP_JSON_FROM_FILE: pops path; pushes value or Nil
|
||||
- OP_JSON_TO_FILE: pops pretty:int(0/1), value, path; pushes 1/0
|
||||
|
||||
Notes:
|
||||
- Requires json-c development headers/libs.
|
||||
- When disabled, functions push empty/neutral values similar to other optional modules.
|
||||
15
docs/external/libsql.md
vendored
Normal file
15
docs/external/libsql.md
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# libSQL extension (optional)
|
||||
|
||||
- CMake option: FUN_WITH_LIBSQL=ON
|
||||
- Purpose: SQLite-compatible client using the libSQL (Turso) library.
|
||||
- Homepage: https://libsql.org/
|
||||
|
||||
Opcodes:
|
||||
- OP_LIBSQL_OPEN: pops url_or_path; pushes handle (>0) or 0
|
||||
- OP_LIBSQL_CLOSE: pops handle; pushes Nil
|
||||
- OP_LIBSQL_EXEC: pops sql, handle; pushes rc:int (0=OK)
|
||||
- OP_LIBSQL_QUERY: pops sql, handle; pushes array<map>
|
||||
|
||||
Notes:
|
||||
- Uses a SQLite-compatible C API provided by libSQL; behavior is similar to the SQLite backend.
|
||||
- This module is independent from the SQLite extension; you may enable either or both.
|
||||
16
docs/external/notcurses.md
vendored
Normal file
16
docs/external/notcurses.md
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Notcurses (TUI) extension (optional)
|
||||
|
||||
- CMake option: FUN_WITH_NOTCURSES=ON
|
||||
- Purpose: Terminal UI capabilities via the Notcurses library.
|
||||
- Homepage: https://notcurses.com/
|
||||
|
||||
Opcodes:
|
||||
- OP_NC_INIT: initialize Notcurses; returns 1 on success, 0 on failure
|
||||
- OP_NC_SHUTDOWN: shutdown; returns 0
|
||||
- OP_NC_CLEAR: clear screen/plane; returns 0
|
||||
- OP_NC_DRAW_TEXT: pops text, x, y; draws; returns 0
|
||||
- OP_NC_GETCH: pops timeout_ms; returns codepoint or -1 on timeout/error
|
||||
|
||||
Notes:
|
||||
- Requires Notcurses development headers/libs.
|
||||
- Behavior may vary across terminals; see the implementation for details.
|
||||
31
docs/external/openssl.md
vendored
Normal file
31
docs/external/openssl.md
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# OpenSSL extension (optional)
|
||||
|
||||
- CMake option: FUN_WITH_OPENSSL=ON
|
||||
- Purpose: provide small crypto helpers backed by OpenSSL. Includes md5, sha256, sha512 helpers.
|
||||
- Homepage: https://www.openssl.org/
|
||||
|
||||
Build notes:
|
||||
- Requires system OpenSSL development headers and libraries.
|
||||
- On OpenSSL 3.x, legacy MD5_* APIs are deprecated; you may see warnings during build.
|
||||
|
||||
Provided helper/opcodes:
|
||||
- Function: openssl_md5(data:string) -> string (lowercase hex). Falls back to empty string when the extension is disabled, mirroring other optional modules.
|
||||
- Function: openssl_sha256(data:string) -> string (lowercase hex).
|
||||
- Function: openssl_sha512(data:string) -> string (lowercase hex).
|
||||
- Opcodes: OP_OPENSSL_MD5, OP_OPENSSL_SHA256, OP_OPENSSL_SHA512 (internal mappings for the functions above).
|
||||
|
||||
Quickstart:
|
||||
- Configure: cmake -S . -B build -DFUN_WITH_OPENSSL=ON
|
||||
- Build: cmake --build build --target fun
|
||||
- Run examples:
|
||||
- ./build/fun examples/crypto/openssl_md5.fun
|
||||
- ./build/fun examples/crypto/openssl_sha256.fun
|
||||
- ./build/fun examples/crypto/openssl_sha512.fun
|
||||
|
||||
Example output:
|
||||
- md5(abc) = 900150983cd24fb0d6963f7d28e17f72
|
||||
- md5("") = d41d8cd98f00b204e9800998ecf8427e
|
||||
- sha256(abc) = ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
|
||||
- sha256("") = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||
- sha512(abc) = ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f
|
||||
- sha512("") = cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
|
||||
14
docs/external/pcre2.md
vendored
Normal file
14
docs/external/pcre2.md
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# PCRE2 (Perl-Compatible Regex) extension (optional)
|
||||
|
||||
- CMake option: FUN_WITH_PCRE2=ON
|
||||
- Purpose: Advanced regular expressions via PCRE2.
|
||||
- Homepage: https://www.pcre.org/
|
||||
|
||||
Opcodes:
|
||||
- OP_PCRE2_TEST: pops flags, text, pattern; pushes 1/0
|
||||
- OP_PCRE2_MATCH: pops flags, text, pattern; pushes match map or Nil
|
||||
- OP_PCRE2_FINDALL: pops flags, text, pattern; pushes array of match maps
|
||||
|
||||
Notes:
|
||||
- Requires PCRE2 development headers/libs.
|
||||
- Flags are backend-specific; see implementation for supported bits.
|
||||
17
docs/external/pcsc.md
vendored
Normal file
17
docs/external/pcsc.md
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# PC/SC (smart cards) extension (optional)
|
||||
|
||||
- CMake option: FUN_WITH_PCSC=ON
|
||||
- Purpose: Access smart card readers/cards via PC/SC (pcsclite).
|
||||
- Homepage: https://pcsclite.apdu.fr/
|
||||
|
||||
Opcodes:
|
||||
- OP_PCSC_ESTABLISH: returns context id (>0) or 0
|
||||
- OP_PCSC_RELEASE: pops ctx id; returns 1/0
|
||||
- OP_PCSC_LIST_READERS: pops ctx id; returns array of reader names
|
||||
- OP_PCSC_CONNECT: pops reader, ctx id; returns handle (>0) or 0
|
||||
- OP_PCSC_DISCONNECT: pops handle id; returns 1/0
|
||||
- OP_PCSC_TRANSMIT: pops apdu, handle id; returns map with data/SW/rc
|
||||
|
||||
Notes:
|
||||
- Requires PC/SC lite development headers/libs.
|
||||
- Behavior and availability depend on platform and reader drivers.
|
||||
15
docs/external/sqlite.md
vendored
Normal file
15
docs/external/sqlite.md
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# SQLite extension (optional)
|
||||
|
||||
- CMake option: FUN_WITH_SQLITE=ON
|
||||
- Purpose: Access SQLite databases via the native C API.
|
||||
- Homepage: https://www.sqlite.org/
|
||||
|
||||
Opcodes:
|
||||
- OP_SQLITE_OPEN: pops path; pushes handle (>0) or 0
|
||||
- OP_SQLITE_CLOSE: pops handle; pushes Nil
|
||||
- OP_SQLITE_EXEC: pops sql, handle; pushes rc:int (0=OK)
|
||||
- OP_SQLITE_QUERY: pops sql, handle; pushes array<map>
|
||||
|
||||
Notes:
|
||||
- Requires SQLite development headers/libs.
|
||||
- See also: `libSQL` for a compatible alternative backend.
|
||||
16
docs/external/tcltk.md
vendored
Normal file
16
docs/external/tcltk.md
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Tcl/Tk (GUI) extension (optional)
|
||||
- CMake option: FUN_WITH_TCLTK=ON
|
||||
- Purpose: Basic GUI functionality via Tcl/Tk.
|
||||
- Homepage: https://www.tcl.tk/
|
||||
Opcodes:
|
||||
- OP_TK_EVAL: pops script string; pushes rc (0=OK)
|
||||
- OP_TK_RESULT: pushes last Tcl result string
|
||||
- OP_TK_LOOP: enters main event loop; pushes Nil when done
|
||||
- OP_TK_WM_TITLE: pops title string; sets window title; pushes rc
|
||||
- OP_TK_LABEL: pops text, id; creates/updates label .id; pushes rc
|
||||
- OP_TK_BUTTON: pops text, id; creates/updates button .id; pushes rc
|
||||
- OP_TK_PACK: pops id; packs .id; pushes rc
|
||||
- OP_TK_BIND: pops command, event, id; binds; pushes rc
|
||||
Notes:
|
||||
- Requires Tcl/Tk development headers/libs.
|
||||
- GUI behavior depends on your desktop environment/window manager.
|
||||
15
docs/external/xml2.md
vendored
Normal file
15
docs/external/xml2.md
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# XML (libxml2) extension (optional)
|
||||
|
||||
- CMake option: FUN_WITH_XML2=ON
|
||||
- Purpose: Minimal XML parsing helpers using libxml2.
|
||||
- Homepage: http://xmlsoft.org/
|
||||
|
||||
Opcodes:
|
||||
- OP_XML_PARSE: pops text; pushes doc handle (>0) or 0
|
||||
- OP_XML_ROOT: pops doc handle; pushes node handle (>0) or 0
|
||||
- OP_XML_NAME: pops node handle; pushes string (node name)
|
||||
- OP_XML_TEXT: pops node handle; pushes string (concatenated text)
|
||||
|
||||
Notes:
|
||||
- Requires libxml2 development headers/libs.
|
||||
- On many systems, the include path is `/usr/include/libxml2`.
|
||||
|
|
@ -5,7 +5,7 @@ Answers to common questions.
|
|||
## I built Fun but includes aren't found
|
||||
Set `FUN_LIB_DIR` to the repository's `./lib` directory when running without installation:
|
||||
```
|
||||
FUN_LIB_DIR=./lib ./build_debug/fun examples/hello.fun
|
||||
FUN_LIB_DIR=./lib ./build/fun examples/hello.fun
|
||||
```
|
||||
See [includes.md](./includes.md).
|
||||
|
||||
|
|
|
|||
|
|
@ -205,7 +205,9 @@ This document provides an overview of the available VM opcodes implemented under
|
|||
## OpenSSL (optional)
|
||||
|
||||
- OP_OPENSSL_MD5: Compute MD5 digest and return lowercase hex string; pops data:string; pushes md5:string.
|
||||
- Requires building with `-DFUN_WITH_OPENSSL=ON`. When disabled, this opcode still exists but returns an empty string to match other optional extensions’ fallback behavior.
|
||||
- OP_OPENSSL_SHA256: Compute SHA‑256 digest and return lowercase hex string; pops data:string; pushes sha256:string.
|
||||
- OP_OPENSSL_SHA512: Compute SHA‑512 digest and return lowercase hex string; pops data:string; pushes sha512:string.
|
||||
- Requires building with `-DFUN_WITH_OPENSSL=ON`. When disabled, these opcodes still exist but return an empty string to match other optional extensions’ fallback behavior.
|
||||
|
||||
## PCRE2 (Regex)
|
||||
|
||||
|
|
|
|||
10
docs/rust.md
10
docs/rust.md
|
|
@ -27,8 +27,8 @@ Rust integration is optional and gated by a CMake flag. Default builds usually h
|
|||
Enable it for a configured profile (Debug or Release):
|
||||
|
||||
- Debug example:
|
||||
cmake -S . -B build_debug -DFUN_WITH_RUST=ON
|
||||
cmake --build build_debug --target fun
|
||||
cmake -S . -B build -DFUN_WITH_RUST=ON
|
||||
cmake --build build --target fun
|
||||
|
||||
- Release example:
|
||||
cmake -S . -B build_release -DFUN_WITH_RUST=ON
|
||||
|
|
@ -137,11 +137,11 @@ Once wired, expose the opcode via a builtin function or directly in bytecode. Th
|
|||
Run the example:
|
||||
|
||||
1) Build with Rust enabled (Debug):
|
||||
cmake -S . -B build_debug -DFUN_WITH_RUST=ON
|
||||
cmake --build build_debug --target fun
|
||||
cmake -S . -B build -DFUN_WITH_RUST=ON
|
||||
cmake --build build --target fun
|
||||
|
||||
2) Execute the script:
|
||||
build_debug/fun examples/rust_hello.fun
|
||||
build/fun examples/rust_hello.fun
|
||||
|
||||
Expected output:
|
||||
Hello from Rust ops!
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ To list targets with CMake directly, consult your IDE or run the build system’
|
|||
Debug profile example:
|
||||
|
||||
```
|
||||
cmake --build build_debug --target test_opcodes && ./build/test_opcodes
|
||||
cmake --build build --target test_opcodes && ./build/test_opcodes
|
||||
```
|
||||
|
||||
Release profile example:
|
||||
|
|
@ -30,14 +30,14 @@ cmake --build build_release --target test_opcodes && ./build/test_opcodes
|
|||
If `fun_test` exists in your configuration:
|
||||
|
||||
```
|
||||
cmake --build build_debug --target fun_test && ./build/fun_test
|
||||
cmake --build build --target fun_test && ./build/fun_test
|
||||
```
|
||||
|
||||
You can also invoke CTest to run any tests registered with `add_test()`:
|
||||
|
||||
```
|
||||
cmake --build build_debug --target test
|
||||
ctest --test-dir build_debug -j
|
||||
cmake --build build --target test
|
||||
ctest --test-dir build -j
|
||||
```
|
||||
|
||||
## Adding new tests
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ Fix:
|
|||
- Build with `-DFUN_WITH_REPL=ON` and rebuild the `fun` target. Then launch without arguments:
|
||||
|
||||
```
|
||||
cmake -S . -B build_debug -DFUN_WITH_REPL=ON
|
||||
cmake --build build_debug --target fun
|
||||
cmake -S . -B build -DFUN_WITH_REPL=ON
|
||||
cmake --build build --target fun
|
||||
FUN_LIB_DIR="$(pwd)/lib" ./build/fun
|
||||
```
|
||||
|
||||
|
|
|
|||
28
examples/crypto/openssl_sha256.fun
Normal file
28
examples/crypto/openssl_sha256.fun
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env fun
|
||||
|
||||
/*
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2026 Johannes Findeisen <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2026-02-19
|
||||
*/
|
||||
|
||||
// OpenSSL SHA-256 example
|
||||
// Enable with -DFUN_WITH_OPENSSL=ON during build for real hashing.
|
||||
|
||||
s = "abc"
|
||||
d = openssl_sha256(s)
|
||||
print("sha256(abc) = " + d)
|
||||
|
||||
// Another quick check (empty string)
|
||||
e = ""
|
||||
print("sha256(\"\") = " + openssl_sha256(e))
|
||||
|
||||
/* Expected output:
|
||||
sha256(abc) = ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
|
||||
sha256("") = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||
*/
|
||||
28
examples/crypto/openssl_sha512.fun
Normal file
28
examples/crypto/openssl_sha512.fun
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env fun
|
||||
|
||||
/*
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2026 Johannes Findeisen <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2026-02-19
|
||||
*/
|
||||
|
||||
// OpenSSL SHA-512 example
|
||||
// Enable with -DFUN_WITH_OPENSSL=ON during build for real hashing.
|
||||
|
||||
s = "abc"
|
||||
d = openssl_sha512(s)
|
||||
print("sha512(abc) = " + d)
|
||||
|
||||
// Another quick check (empty string)
|
||||
e = ""
|
||||
print("sha512(\"\") = " + openssl_sha512(e))
|
||||
|
||||
/* Expected output:
|
||||
sha512(abc) = ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f
|
||||
sha512("") = cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
|
||||
*/
|
||||
5
make
5
make
|
|
@ -32,6 +32,7 @@ if [ "$target" = "all" ]; then
|
|||
-DFUN_WITH_INI=ON \
|
||||
-DFUN_WITH_NOTCURSES=ON \
|
||||
-DFUN_WITH_CPP=ON \
|
||||
-DFUN_WITH_OPENSSL=ON \
|
||||
&& cmake --build build --target fun
|
||||
elif [ "$target" = "all_debug" ]; then
|
||||
rm -rf build \
|
||||
|
|
@ -48,6 +49,7 @@ elif [ "$target" = "all_debug" ]; then
|
|||
-DFUN_WITH_INI=ON \
|
||||
-DFUN_WITH_NOTCURSES=ON \
|
||||
-DFUN_WITH_CPP=ON \
|
||||
-DFUN_WITH_OPENSSL=ON \
|
||||
-DFUN_DEBUG=ON \
|
||||
&& cmake --build build --target fun
|
||||
elif [ "$target" = "alpine" ]; then
|
||||
|
|
@ -62,6 +64,7 @@ elif [ "$target" = "alpine" ]; then
|
|||
-DFUN_WITH_JSON=ON \
|
||||
-DFUN_WITH_INI=ON \
|
||||
-DFUN_WITH_CPP=ON \
|
||||
-DFUN_WITH_OPENSSL=ON \
|
||||
&& cmake --build build --target fun
|
||||
elif [ "$target" = "cpp_all" ]; then
|
||||
rm -rf build \
|
||||
|
|
@ -78,6 +81,7 @@ elif [ "$target" = "cpp_all" ]; then
|
|||
-DFUN_WITH_INI=ON \
|
||||
-DFUN_WITH_NOTCURSES=ON \
|
||||
-DFUN_WITH_CPP=ON \
|
||||
-DFUN_WITH_OPENSSL=ON \
|
||||
&& cmake --build build --target fun
|
||||
elif [ "$target" = "cpp_minimal" ]; then
|
||||
rm -rf build \
|
||||
|
|
@ -133,6 +137,7 @@ elif [ "$target" = "rust_all" ]; then
|
|||
-DFUN_WITH_INI=ON \
|
||||
-DFUN_WITH_RUST=ON \
|
||||
-DFUN_WITH_CPP=ON \
|
||||
-DFUN_WITH_OPENSSL=ON \
|
||||
-DFUN_DEBUG=OFF \
|
||||
&& cmake --build build --target fun
|
||||
elif [ "$target" = "rust_minimal" ]; then
|
||||
|
|
|
|||
|
|
@ -170,6 +170,8 @@ static const char *opcode_name(OpCode op) {
|
|||
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_INI_LOAD: return "INI_LOAD";
|
||||
case OP_INI_FREE: return "INI_FREE";
|
||||
case OP_INI_GET_STRING: return "INI_GET_STRING";
|
||||
|
|
|
|||
|
|
@ -183,6 +183,8 @@ typedef enum {
|
|||
|
||||
// OpenSSL (optional)
|
||||
OP_OPENSSL_MD5, // pops data string; pushes md5 hex string
|
||||
OP_OPENSSL_SHA256, // pops data string; pushes sha256 hex string
|
||||
OP_OPENSSL_SHA512, // pops data string; pushes sha512 hex string
|
||||
|
||||
// INI (iniparser 4.2.6) optional
|
||||
OP_INI_LOAD, // pops path; pushes handle (>0) or 0
|
||||
|
|
|
|||
130
src/external/openssl.c
vendored
Normal file
130
src/external/openssl.c
vendored
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2025 Johannes Findeisen <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2026-02-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* OpenSSL integration helpers (MD5, SHA-256, SHA-512)
|
||||
*/
|
||||
|
||||
#ifdef FUN_WITH_OPENSSL
|
||||
# include <openssl/evp.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Compute MD5 hex of input buffer; returns malloc'ed C string (lowercase hex).
|
||||
* Caller must free(). Returns NULL on failure. When OpenSSL is disabled,
|
||||
* returns an allocated empty string ("") to keep behavior consistent with
|
||||
* other optional extensions. */
|
||||
static char *fun_openssl_md5_hex(const unsigned char *data, size_t len) {
|
||||
static const char hexdig[] = "0123456789abcdef";
|
||||
if (!data && len != 0) return NULL;
|
||||
#ifdef FUN_WITH_OPENSSL
|
||||
const EVP_MD *md = EVP_md5();
|
||||
if (!md) return NULL;
|
||||
int dlen = EVP_MD_get_size(md);
|
||||
if (dlen <= 0) return NULL;
|
||||
unsigned char *digest = (unsigned char*)malloc((size_t)dlen);
|
||||
if (!digest) return NULL;
|
||||
unsigned int out_len = 0;
|
||||
int ok;
|
||||
if (len == 0) {
|
||||
// EVP_Digest handles zero-length fine as well
|
||||
ok = EVP_Digest(NULL, 0, digest, &out_len, md, NULL);
|
||||
} else {
|
||||
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
||||
}
|
||||
if (ok != 1 || (int)out_len != dlen) { free(digest); return NULL; }
|
||||
char *hex = (char*)malloc((size_t)dlen * 2 + 1);
|
||||
if (!hex) { free(digest); return NULL; }
|
||||
for (int i = 0; i < dlen; ++i) {
|
||||
hex[2*i] = hexdig[(digest[i] >> 4) & 0xF];
|
||||
hex[2*i+1] = hexdig[digest[i] & 0xF];
|
||||
}
|
||||
hex[dlen * 2] = '\0';
|
||||
free(digest);
|
||||
return hex;
|
||||
#else
|
||||
char *hex = (char*)malloc(1);
|
||||
if (hex) hex[0] = '\0';
|
||||
return hex;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Compute SHA-256 hex of input buffer; returns malloc'ed C string (lowercase hex).
|
||||
* Fallback when OpenSSL disabled: empty string. */
|
||||
static char *fun_openssl_sha256_hex(const unsigned char *data, size_t len) {
|
||||
static const char hexdig[] = "0123456789abcdef";
|
||||
if (!data && len != 0) return NULL;
|
||||
#ifdef FUN_WITH_OPENSSL
|
||||
const EVP_MD *md = EVP_sha256();
|
||||
if (!md) return NULL;
|
||||
int dlen = EVP_MD_get_size(md);
|
||||
if (dlen <= 0) return NULL;
|
||||
unsigned char *digest = (unsigned char*)malloc((size_t)dlen);
|
||||
if (!digest) return NULL;
|
||||
unsigned int out_len = 0;
|
||||
int ok;
|
||||
if (len == 0) {
|
||||
ok = EVP_Digest(NULL, 0, digest, &out_len, md, NULL);
|
||||
} else {
|
||||
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
||||
}
|
||||
if (ok != 1 || (int)out_len != dlen) { free(digest); return NULL; }
|
||||
char *hex = (char*)malloc((size_t)dlen * 2 + 1);
|
||||
if (!hex) { free(digest); return NULL; }
|
||||
for (int i = 0; i < dlen; ++i) {
|
||||
hex[2*i] = hexdig[(digest[i] >> 4) & 0xF];
|
||||
hex[2*i+1] = hexdig[digest[i] & 0xF];
|
||||
}
|
||||
hex[dlen * 2] = '\0';
|
||||
free(digest);
|
||||
return hex;
|
||||
#else
|
||||
char *hex = (char*)malloc(1);
|
||||
if (hex) hex[0] = '\0';
|
||||
return hex;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Compute SHA-512 hex of input buffer; returns malloc'ed C string (lowercase hex).
|
||||
* Fallback when OpenSSL disabled: empty string. */
|
||||
static char *fun_openssl_sha512_hex(const unsigned char *data, size_t len) {
|
||||
static const char hexdig[] = "0123456789abcdef";
|
||||
if (!data && len != 0) return NULL;
|
||||
#ifdef FUN_WITH_OPENSSL
|
||||
const EVP_MD *md = EVP_sha512();
|
||||
if (!md) return NULL;
|
||||
int dlen = EVP_MD_get_size(md);
|
||||
if (dlen <= 0) return NULL;
|
||||
unsigned char *digest = (unsigned char*)malloc((size_t)dlen);
|
||||
if (!digest) return NULL;
|
||||
unsigned int out_len = 0;
|
||||
int ok;
|
||||
if (len == 0) {
|
||||
ok = EVP_Digest(NULL, 0, digest, &out_len, md, NULL);
|
||||
} else {
|
||||
ok = EVP_Digest(data, len, digest, &out_len, md, NULL);
|
||||
}
|
||||
if (ok != 1 || (int)out_len != dlen) { free(digest); return NULL; }
|
||||
char *hex = (char*)malloc((size_t)dlen * 2 + 1);
|
||||
if (!hex) { free(digest); return NULL; }
|
||||
for (int i = 0; i < dlen; ++i) {
|
||||
hex[2*i] = hexdig[(digest[i] >> 4) & 0xF];
|
||||
hex[2*i+1] = hexdig[digest[i] & 0xF];
|
||||
}
|
||||
hex[dlen * 2] = '\0';
|
||||
free(digest);
|
||||
return hex;
|
||||
#else
|
||||
char *hex = (char*)malloc(1);
|
||||
if (hex) hex[0] = '\0';
|
||||
return hex;
|
||||
#endif
|
||||
}
|
||||
47
src/external/opensssl.c
vendored
47
src/external/opensssl.c
vendored
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Fun programming language.
|
||||
* https://fun-lang.xyz/
|
||||
*
|
||||
* Copyright 2025 Johannes Findeisen <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*
|
||||
* Added: 2026-02-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* OpenSSL integration helpers (currently MD5 only)
|
||||
*/
|
||||
|
||||
#ifdef FUN_WITH_OPENSSL
|
||||
# include <openssl/md5.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Compute MD5 hex of input buffer; returns malloc'ed C string (lowercase hex).
|
||||
* Caller must free(). Returns NULL on failure. When OpenSSL is disabled,
|
||||
* returns an allocated empty string ("") to keep behavior consistent with
|
||||
* other optional extensions. */
|
||||
static char *fun_openssl_md5_hex(const unsigned char *data, size_t len) {
|
||||
static const char hexdig[] = "0123456789abcdef";
|
||||
if (!data && len != 0) return NULL;
|
||||
#ifdef FUN_WITH_OPENSSL
|
||||
unsigned char digest[MD5_DIGEST_LENGTH];
|
||||
MD5_CTX ctx;
|
||||
if (MD5_Init(&ctx) != 1) return NULL;
|
||||
if (len && MD5_Update(&ctx, data, len) != 1) return NULL;
|
||||
if (MD5_Final(digest, &ctx) != 1) return NULL;
|
||||
char *hex = (char*)malloc(MD5_DIGEST_LENGTH * 2 + 1);
|
||||
if (!hex) return NULL;
|
||||
for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
|
||||
hex[2*i] = hexdig[(digest[i] >> 4) & 0xF];
|
||||
hex[2*i+1] = hexdig[digest[i] & 0xF];
|
||||
}
|
||||
hex[MD5_DIGEST_LENGTH * 2] = '\0';
|
||||
return hex;
|
||||
#else
|
||||
char *hex = (char*)malloc(1);
|
||||
if (hex) hex[0] = '\0';
|
||||
return hex;
|
||||
#endif
|
||||
}
|
||||
18
src/parser.c
18
src/parser.c
|
|
@ -1197,7 +1197,7 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos)
|
|||
free(name);
|
||||
return 1;
|
||||
}
|
||||
/* OpenSSL (md5) */
|
||||
/* OpenSSL (md5/sha256/sha512) */
|
||||
if (strcmp(name, "openssl_md5") == 0) {
|
||||
(*pos)++; /* '(' */
|
||||
if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "openssl_md5 expects (data)"); free(name); return 0; }
|
||||
|
|
@ -1206,6 +1206,22 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos)
|
|||
free(name);
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(name, "openssl_sha256") == 0) {
|
||||
(*pos)++; /* '(' */
|
||||
if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "openssl_sha256 expects (data)"); free(name); return 0; }
|
||||
if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after openssl_sha256 arg"); free(name); return 0; }
|
||||
bytecode_add_instruction(bc, OP_OPENSSL_SHA256, 0);
|
||||
free(name);
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(name, "openssl_sha512") == 0) {
|
||||
(*pos)++; /* '(' */
|
||||
if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "openssl_sha512 expects (data)"); free(name); return 0; }
|
||||
if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after openssl_sha512 arg"); free(name); return 0; }
|
||||
bytecode_add_instruction(bc, OP_OPENSSL_SHA512, 0);
|
||||
free(name);
|
||||
return 1;
|
||||
}
|
||||
/* PCSC builtins */
|
||||
if (strcmp(name, "pcsc_establish") == 0) {
|
||||
(*pos)++; /* '(' */
|
||||
|
|
|
|||
6
src/vm.c
6
src/vm.c
|
|
@ -73,7 +73,7 @@
|
|||
#include "external/sqlite.c"
|
||||
#include "external/tcltk.c"
|
||||
#include "external/xml2.c"
|
||||
#include "external/opensssl.c"
|
||||
#include "external/openssl.c"
|
||||
|
||||
/* forward declarations for include mapping used in error reporting */
|
||||
extern char *preprocess_includes(const char *src);
|
||||
|
|
@ -869,8 +869,10 @@ void vm_run(VM *vm, Bytecode *entry) {
|
|||
#include "vm/curl/download.c"
|
||||
#endif
|
||||
|
||||
/* OpenSSL ops (md5) */
|
||||
/* OpenSSL ops (md5/sha256/sha512) */
|
||||
#include "vm/openssl/md5.c"
|
||||
#include "vm/openssl/sha256.c"
|
||||
#include "vm/openssl/sha512.c"
|
||||
|
||||
/* Tk (Tcl/Tk) ops */
|
||||
#ifdef FUN_WITH_TCLTK
|
||||
|
|
|
|||
16
src/vm/openssl/sha256.c
Normal file
16
src/vm/openssl/sha256.c
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* OpenSSL SHA-256 builtin
|
||||
*/
|
||||
case OP_OPENSSL_SHA256: {
|
||||
Value vdata = pop_value(vm);
|
||||
char *s = value_to_string_alloc(&vdata);
|
||||
free_value(vdata);
|
||||
if (!s) { push_value(vm, make_string("")); break; }
|
||||
char *hex = fun_openssl_sha256_hex((const unsigned char*)s, strlen(s));
|
||||
free(s);
|
||||
if (!hex) { push_value(vm, make_string("")); break; }
|
||||
Value out = make_string(hex);
|
||||
free(hex);
|
||||
push_value(vm, out);
|
||||
break;
|
||||
}
|
||||
16
src/vm/openssl/sha512.c
Normal file
16
src/vm/openssl/sha512.c
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* OpenSSL SHA-512 builtin
|
||||
*/
|
||||
case OP_OPENSSL_SHA512: {
|
||||
Value vdata = pop_value(vm);
|
||||
char *s = value_to_string_alloc(&vdata);
|
||||
free_value(vdata);
|
||||
if (!s) { push_value(vm, make_string("")); break; }
|
||||
char *hex = fun_openssl_sha512_hex((const unsigned char*)s, strlen(s));
|
||||
free(s);
|
||||
if (!hex) { push_value(vm, make_string("")); break; }
|
||||
Value out = make_string(hex);
|
||||
free(hex);
|
||||
push_value(vm, out);
|
||||
break;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue