Added libcurl (cURL) support. (0.30.0)
This commit is contained in:
parent
bb848b6679
commit
4d82d73515
15 changed files with 304 additions and 8 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -7,6 +7,7 @@ build*
|
||||||
cmake*
|
cmake*
|
||||||
demo_*
|
demo_*
|
||||||
dist/
|
dist/
|
||||||
|
downloaded.png
|
||||||
lib/*.so
|
lib/*.so
|
||||||
out/
|
out/
|
||||||
src/*.o
|
src/*.o
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(fun VERSION 0.29.0 LANGUAGES C)
|
project(fun VERSION 0.30.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)
|
||||||
|
|
@ -87,6 +87,26 @@ if(FUN_WITH_PCRE2)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Optional CURL (libcurl) support
|
||||||
|
option(FUN_WITH_CURL "Enable libcurl HTTP client support" OFF)
|
||||||
|
set(CURL_INCLUDE_DIRS "")
|
||||||
|
set(CURL_LINK_LIBS "")
|
||||||
|
if(FUN_WITH_CURL)
|
||||||
|
message(STATUS "Building with libcurl support")
|
||||||
|
add_definitions(-DFUN_WITH_CURL)
|
||||||
|
find_package(PkgConfig QUIET)
|
||||||
|
if(PKG_CONFIG_FOUND)
|
||||||
|
pkg_check_modules(LIBCURL QUIET libcurl)
|
||||||
|
endif()
|
||||||
|
if(LIBCURL_FOUND)
|
||||||
|
list(APPEND CURL_INCLUDE_DIRS ${LIBCURL_INCLUDE_DIRS})
|
||||||
|
list(APPEND CURL_LINK_LIBS ${LIBCURL_LIBRARIES})
|
||||||
|
include_directories(${CURL_INCLUDE_DIRS})
|
||||||
|
else()
|
||||||
|
list(APPEND CURL_LINK_LIBS curl)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
# Debug option to enable verbose parser/VM logging
|
# Debug option to enable verbose parser/VM logging
|
||||||
option(FUN_DEBUG "Enable extra debug logging in Fun" OFF)
|
option(FUN_DEBUG "Enable extra debug logging in Fun" OFF)
|
||||||
|
|
||||||
|
|
@ -140,6 +160,14 @@ if(PCRE2_LINK_LIBS)
|
||||||
target_link_libraries(fun_core PUBLIC ${PCRE2_LINK_LIBS})
|
target_link_libraries(fun_core PUBLIC ${PCRE2_LINK_LIBS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# libcurl include and link (if enabled)
|
||||||
|
if(CURL_INCLUDE_DIRS)
|
||||||
|
target_include_directories(fun_core PRIVATE ${CURL_INCLUDE_DIRS})
|
||||||
|
endif()
|
||||||
|
if(CURL_LINK_LIBS)
|
||||||
|
target_link_libraries(fun_core PUBLIC ${CURL_LINK_LIBS})
|
||||||
|
endif()
|
||||||
|
|
||||||
# Link threads if available on UNIX
|
# Link threads if available on UNIX
|
||||||
if(Threads_FOUND)
|
if(Threads_FOUND)
|
||||||
target_link_libraries(fun_core PUBLIC Threads::Threads)
|
target_link_libraries(fun_core PUBLIC Threads::Threads)
|
||||||
|
|
|
||||||
10
README.md
10
README.md
|
|
@ -17,9 +17,9 @@ Fun is and will ever be 100% free under the terms of the [Apache-2.0 License](ht
|
||||||
|
|
||||||
### Extras
|
### Extras
|
||||||
|
|
||||||
|
- [cURL](https://curl.se/) support builtin using [libcurl](https://curl.se/libcurl/) (optional) ☑
|
||||||
- [JSON](https://www.json.org/) support builtin using [json-c](https://github.com/json-c/json-c) (optional) ☑
|
- [JSON](https://www.json.org/) support builtin using [json-c](https://github.com/json-c/json-c) (optional) ☑
|
||||||
- [ODBC](https://learn.microsoft.com/en-us/sql/odbc/reference/odbc-overview?view=sql-server-ver16) support builtin for flexible database connectivity using [unixODBC](https://www.unixodbc.org/) (optional) ☐
|
- [PCSC](https://pcscworkgroup.com/) smart card support builtin using [PCSC lite](https://pcsclite.apdu.fr/) (optional) ☑
|
||||||
- [PC/SC](https://pcscworkgroup.com/) smart card support builtin using [PCSC lite](https://pcsclite.apdu.fr/) (optional) ☑
|
|
||||||
- [PCRE2](https://pcre2project.github.io/pcre2/) support builtin for Perl-Compatible Regular Expressions (optional) ☑
|
- [PCRE2](https://pcre2project.github.io/pcre2/) support builtin for Perl-Compatible Regular Expressions (optional) ☑
|
||||||
- [SQLite](https://sqlite.org/) support builtin (optional) ☐
|
- [SQLite](https://sqlite.org/) support builtin (optional) ☐
|
||||||
- [Tk](https://www.tcl-lang.org/) support builtin for GUI application development (optional) ☐
|
- [Tk](https://www.tcl-lang.org/) support builtin for GUI application development (optional) ☐
|
||||||
|
|
@ -138,9 +138,11 @@ cmake --build build --target fun
|
||||||
CMake options you can toggle (all require NAME=VALUE):
|
CMake options you can toggle (all require NAME=VALUE):
|
||||||
|
|
||||||
- FUN_DEBUG=ON|OFF — verbose debug logging in the VM (default OFF)
|
- FUN_DEBUG=ON|OFF — verbose debug logging in the VM (default OFF)
|
||||||
- FUN_WITH_REPL=ON|OFF — enable building the interactive REPL (default ON)
|
- FUN_WITH_CURL=ON|OFF — enable CURL support using libcurl (default OFF)
|
||||||
- FUN_WITH_PCSC=ON|OFF — enable PC/SC smart card support (default OFF)
|
|
||||||
- FUN_WITH_JSON=ON|OFF — enable JSON support via json-c (default OFF)
|
- FUN_WITH_JSON=ON|OFF — enable JSON support via json-c (default OFF)
|
||||||
|
- FUN_WITH_PCRE2=ON|OFF — enable PCRE2 Perl-Compatible Regular Expressions support (default OFF)
|
||||||
|
- FUN_WITH_PCSC=ON|OFF — enable PCSC smart card support (default OFF)
|
||||||
|
- FUN_WITH_REPL=ON|OFF — enable the interactive REPL (default ON)
|
||||||
|
|
||||||
That's it! For testing it, run:
|
That's it! For testing it, run:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,10 +85,11 @@ But be sure to build Fun with -DFUN_WITH_REPL=ON.
|
||||||
All CMake options must be passed as -DNAME=VALUE:
|
All CMake options must be passed as -DNAME=VALUE:
|
||||||
|
|
||||||
- FUN_DEBUG=ON|OFF — verbose debug logging in the VM (default OFF)
|
- FUN_DEBUG=ON|OFF — verbose debug logging in the VM (default OFF)
|
||||||
- FUN_WITH_REPL=ON|OFF — enable the interactive REPL (default ON)
|
- FUN_WITH_CURL=ON|OFF — enable CURL support using libcurl (default OFF)
|
||||||
- FUN_WITH_PCRE2=ON|OFF — enable PCRE2 Perl-Compatible Regular Expressions support (default OFF)
|
|
||||||
- FUN_WITH_PCSC=ON|OFF — enable PC/SC smart card support (default OFF)
|
|
||||||
- FUN_WITH_JSON=ON|OFF — enable JSON support via json-c (default OFF)
|
- FUN_WITH_JSON=ON|OFF — enable JSON support via json-c (default OFF)
|
||||||
|
- FUN_WITH_PCRE2=ON|OFF — enable PCRE2 Perl-Compatible Regular Expressions support (default OFF)
|
||||||
|
- FUN_WITH_PCSC=ON|OFF — enable PCSC smart card support (default OFF)
|
||||||
|
- FUN_WITH_REPL=ON|OFF — enable the interactive REPL (default ON)
|
||||||
|
|
||||||
If you encounter an error such as:
|
If you encounter an error such as:
|
||||||
|
|
||||||
|
|
|
||||||
24
examples/curl_download.fun
Normal file
24
examples/curl_download.fun
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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: 2025-11-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Demonstrates curl_download saving a file to disk.
|
||||||
|
*/
|
||||||
|
|
||||||
|
url = "https://httpbin.org/image/png"
|
||||||
|
path = "./downloaded.png"
|
||||||
|
ok = curl_download(url, path)
|
||||||
|
if ok == 1
|
||||||
|
print("Downloaded to " + path)
|
||||||
|
else
|
||||||
|
print("Download failed")
|
||||||
25
examples/curl_get_json.fun
Normal file
25
examples/curl_get_json.fun
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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: 2025-11-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Demonstrates curl_get and JSON.parse working together.
|
||||||
|
*/
|
||||||
|
|
||||||
|
url = "https://httpbin.org/json"
|
||||||
|
resp = curl_get(url)
|
||||||
|
print("Raw length: " + to_string(len(resp)))
|
||||||
|
|
||||||
|
// If JSON support is enabled, parse it
|
||||||
|
obj = json_parse(resp)
|
||||||
|
if obj != nil
|
||||||
|
print("Title: " + obj["slideshow"]["title"])
|
||||||
32
examples/curl_post.fun
Normal file
32
examples/curl_post.fun
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#!/usr/bin/env fun
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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: 2025-11-25
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Demonstrates curl_post sending form data and printing response.
|
||||||
|
*/
|
||||||
|
|
||||||
|
url = "https://httpbin.org/post"
|
||||||
|
data = "name=Fun&lang=fun"
|
||||||
|
resp = curl_post(url, data)
|
||||||
|
print("Response: " + resp)
|
||||||
|
|
||||||
|
// If JSON support is enabled, parse it
|
||||||
|
obj = json_parse(resp)
|
||||||
|
if obj != nil
|
||||||
|
print("Content-Type: " + to_string(obj["headers"]["Content-Type"]))
|
||||||
|
|
||||||
|
if obj != nil
|
||||||
|
print("Host: " + to_string(obj["headers"]["Host"]))
|
||||||
|
|
||||||
|
if obj != nil
|
||||||
|
print("Origin: " + to_string(obj["origin"]))
|
||||||
|
|
@ -145,6 +145,9 @@ static const char *opcode_name(OpCode op) {
|
||||||
case OP_JSON_STRINGIFY: return "JSON_STRINGIFY";
|
case OP_JSON_STRINGIFY: return "JSON_STRINGIFY";
|
||||||
case OP_JSON_FROM_FILE: return "JSON_FROM_FILE";
|
case OP_JSON_FROM_FILE: return "JSON_FROM_FILE";
|
||||||
case OP_JSON_TO_FILE: return "JSON_TO_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_PCSC_ESTABLISH: return "PCSC_ESTABLISH";
|
case OP_PCSC_ESTABLISH: return "PCSC_ESTABLISH";
|
||||||
case OP_PCSC_RELEASE: return "PCSC_RELEASE";
|
case OP_PCSC_RELEASE: return "PCSC_RELEASE";
|
||||||
case OP_PCSC_LIST_READERS: return "PCSC_LIST_READERS";
|
case OP_PCSC_LIST_READERS: return "PCSC_LIST_READERS";
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,11 @@ typedef enum {
|
||||||
OP_JSON_FROM_FILE, // pops path string; pushes value (or Nil)
|
OP_JSON_FROM_FILE, // pops path string; pushes value (or Nil)
|
||||||
OP_JSON_TO_FILE, // pops pretty(bool), value, path; pushes 1/0
|
OP_JSON_TO_FILE, // pops pretty(bool), value, path; pushes 1/0
|
||||||
|
|
||||||
|
// CURL (libcurl)
|
||||||
|
OP_CURL_GET, // pops [headers map?], url; pushes response string (or "")
|
||||||
|
OP_CURL_POST, // pops [headers map?], body string, url; pushes response string (or "")
|
||||||
|
OP_CURL_DOWNLOAD, // pops [headers map?], path, url; pushes 1/0
|
||||||
|
|
||||||
// PCSC (smart card) opcodes
|
// PCSC (smart card) opcodes
|
||||||
OP_PCSC_ESTABLISH, // returns context id (>0) or 0
|
OP_PCSC_ESTABLISH, // returns context id (>0) or 0
|
||||||
OP_PCSC_RELEASE, // pops ctx id; returns 1/0
|
OP_PCSC_RELEASE, // pops ctx id; returns 1/0
|
||||||
|
|
|
||||||
29
src/parser.c
29
src/parser.c
|
|
@ -778,6 +778,35 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos)
|
||||||
free(name);
|
free(name);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
/* CURL builtins (minimal interface like JSON) */
|
||||||
|
if (strcmp(name, "curl_get") == 0) {
|
||||||
|
(*pos)++; /* '(' */
|
||||||
|
if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "curl_get expects (url)"); free(name); return 0; }
|
||||||
|
if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after curl_get arg"); free(name); return 0; }
|
||||||
|
bytecode_add_instruction(bc, OP_CURL_GET, 0);
|
||||||
|
free(name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (strcmp(name, "curl_post") == 0) {
|
||||||
|
(*pos)++; /* '(' */
|
||||||
|
if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "curl_post expects (url, body)"); free(name); return 0; }
|
||||||
|
if (!consume_char(src, len, pos, ',')) { parser_fail(*pos, "curl_post expects (url, body)"); free(name); return 0; }
|
||||||
|
if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "curl_post expects (url, body)"); free(name); return 0; }
|
||||||
|
if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after curl_post args"); free(name); return 0; }
|
||||||
|
bytecode_add_instruction(bc, OP_CURL_POST, 0);
|
||||||
|
free(name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (strcmp(name, "curl_download") == 0) {
|
||||||
|
(*pos)++; /* '(' */
|
||||||
|
if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "curl_download expects (url, path)"); free(name); return 0; }
|
||||||
|
if (!consume_char(src, len, pos, ',')) { parser_fail(*pos, "curl_download expects (url, path)"); free(name); return 0; }
|
||||||
|
if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "curl_download expects (url, path)"); free(name); return 0; }
|
||||||
|
if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after curl_download args"); free(name); return 0; }
|
||||||
|
bytecode_add_instruction(bc, OP_CURL_DOWNLOAD, 0);
|
||||||
|
free(name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
/* PCSC builtins */
|
/* PCSC builtins */
|
||||||
if (strcmp(name, "pcsc_establish") == 0) {
|
if (strcmp(name, "pcsc_establish") == 0) {
|
||||||
(*pos)++; /* '(' */
|
(*pos)++; /* '(' */
|
||||||
|
|
|
||||||
24
src/vm.c
24
src/vm.c
|
|
@ -32,6 +32,25 @@
|
||||||
#include <pcre2.h>
|
#include <pcre2.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Ensure libcurl headers and helpers are defined at file scope (not inside vm_run) */
|
||||||
|
#ifdef FUN_WITH_CURL
|
||||||
|
#include <curl/curl.h>
|
||||||
|
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) {
|
||||||
|
size_t add = sz * nm;
|
||||||
|
FunCurlBuf *b = (FunCurlBuf*)ud;
|
||||||
|
char *p = (char*)realloc(b->d, b->n + add + 1);
|
||||||
|
if (!p) return 0;
|
||||||
|
memcpy(p + b->n, ptr, add);
|
||||||
|
b->d = p; b->n += add; b->d[b->n] = '\0';
|
||||||
|
return add;
|
||||||
|
}
|
||||||
|
static size_t fun_curl_file_write_cb(void *ptr, size_t sz, size_t nm, void *ud) {
|
||||||
|
FILE *f = (FILE*)ud;
|
||||||
|
return fwrite(ptr, sz, nm, f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* 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);
|
||||||
static int map_expanded_line_to_include(const char *path, int line, char *out_path, size_t out_path_cap, int *out_line);
|
static int map_expanded_line_to_include(const char *path, int line, char *out_path, size_t out_path_cap, int *out_line);
|
||||||
|
|
@ -679,6 +698,11 @@ void vm_run(VM *vm, Bytecode *entry) {
|
||||||
#include "vm/json/from_file.c"
|
#include "vm/json/from_file.c"
|
||||||
#include "vm/json/to_file.c"
|
#include "vm/json/to_file.c"
|
||||||
|
|
||||||
|
/* CURL ops */
|
||||||
|
#include "vm/curl/get.c"
|
||||||
|
#include "vm/curl/post.c"
|
||||||
|
#include "vm/curl/download.c"
|
||||||
|
|
||||||
/* PCRE2 ops */
|
/* PCRE2 ops */
|
||||||
#include "vm/pcre2/test.c"
|
#include "vm/pcre2/test.c"
|
||||||
#include "vm/pcre2/match.c"
|
#include "vm/pcre2/match.c"
|
||||||
|
|
|
||||||
1
src/vm.h
1
src/vm.h
|
|
@ -39,6 +39,7 @@ static const char *opcode_names[] = {
|
||||||
"THREAD_SPAWN","THREAD_JOIN","SLEEP_MS",
|
"THREAD_SPAWN","THREAD_JOIN","SLEEP_MS",
|
||||||
"BAND","BOR","BXOR","BNOT","SHL","SHR","ROTL","ROTR",
|
"BAND","BOR","BXOR","BNOT","SHL","SHR","ROTL","ROTR",
|
||||||
"JSON_PARSE","JSON_STRINGIFY","JSON_FROM_FILE","JSON_TO_FILE",
|
"JSON_PARSE","JSON_STRINGIFY","JSON_FROM_FILE","JSON_TO_FILE",
|
||||||
|
"CURL_GET","CURL_POST","CURL_DOWNLOAD",
|
||||||
"PCSC_ESTABLISH","PCSC_RELEASE","PCSC_LIST_READERS","PCSC_CONNECT","PCSC_DISCONNECT","PCSC_TRANSMIT",
|
"PCSC_ESTABLISH","PCSC_RELEASE","PCSC_LIST_READERS","PCSC_CONNECT","PCSC_DISCONNECT","PCSC_TRANSMIT",
|
||||||
"PCRE2_TEST","PCRE2_MATCH","PCRE2_FINDALL",
|
"PCRE2_TEST","PCRE2_MATCH","PCRE2_FINDALL",
|
||||||
"SOCK_TCP_LISTEN","SOCK_TCP_ACCEPT","SOCK_TCP_CONNECT","SOCK_SEND","SOCK_RECV","SOCK_CLOSE","SOCK_UNIX_LISTEN","SOCK_UNIX_CONNECT",
|
"SOCK_TCP_LISTEN","SOCK_TCP_ACCEPT","SOCK_TCP_CONNECT","SOCK_SEND","SOCK_RECV","SOCK_CLOSE","SOCK_UNIX_LISTEN","SOCK_UNIX_CONNECT",
|
||||||
|
|
|
||||||
47
src/vm/curl/download.c
Normal file
47
src/vm/curl/download.c
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
/**
|
||||||
|
* libcurl DOWNLOAD builtin
|
||||||
|
*/
|
||||||
|
case OP_CURL_DOWNLOAD: {
|
||||||
|
#ifdef FUN_WITH_CURL
|
||||||
|
Value vpath = pop_value(vm);
|
||||||
|
Value vurl = pop_value(vm);
|
||||||
|
char *url = value_to_string_alloc(&vurl);
|
||||||
|
char *path = value_to_string_alloc(&vpath);
|
||||||
|
free_value(vurl);
|
||||||
|
free_value(vpath);
|
||||||
|
if (!url || !path) {
|
||||||
|
if (url) free(url);
|
||||||
|
if (path) free(path);
|
||||||
|
push_value(vm, make_int(0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
FILE *fp = fopen(path, "wb");
|
||||||
|
if (!fp) {
|
||||||
|
free(url); free(path);
|
||||||
|
push_value(vm, make_int(0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CURL *h = curl_easy_init();
|
||||||
|
if (!h) {
|
||||||
|
fclose(fp);
|
||||||
|
free(url); free(path);
|
||||||
|
push_value(vm, make_int(0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
curl_easy_setopt(h, CURLOPT_URL, url);
|
||||||
|
curl_easy_setopt(h, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
curl_easy_setopt(h, CURLOPT_WRITEFUNCTION, fun_curl_file_write_cb);
|
||||||
|
curl_easy_setopt(h, CURLOPT_WRITEDATA, fp);
|
||||||
|
CURLcode rc = curl_easy_perform(h);
|
||||||
|
curl_easy_cleanup(h);
|
||||||
|
fclose(fp);
|
||||||
|
free(url); free(path);
|
||||||
|
if (rc != CURLE_OK) { push_value(vm, make_int(0)); break; }
|
||||||
|
push_value(vm, make_int(1));
|
||||||
|
#else
|
||||||
|
Value a = pop_value(vm); free_value(a);
|
||||||
|
Value b = pop_value(vm); free_value(b);
|
||||||
|
push_value(vm, make_int(0));
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
33
src/vm/curl/get.c
Normal file
33
src/vm/curl/get.c
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
* libcurl GET builtin
|
||||||
|
*/
|
||||||
|
case OP_CURL_GET: {
|
||||||
|
#ifdef FUN_WITH_CURL
|
||||||
|
Value vurl = pop_value(vm);
|
||||||
|
char *url = value_to_string_alloc(&vurl);
|
||||||
|
free_value(vurl);
|
||||||
|
if (!url) { push_value(vm, make_string("")); break; }
|
||||||
|
FunCurlBuf buf = { NULL, 0 };
|
||||||
|
CURL *h = curl_easy_init();
|
||||||
|
if (!h) { free(url); push_value(vm, make_string("")); break; }
|
||||||
|
curl_easy_setopt(h, CURLOPT_URL, url);
|
||||||
|
curl_easy_setopt(h, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
curl_easy_setopt(h, CURLOPT_WRITEFUNCTION, fun_curl_write_cb);
|
||||||
|
curl_easy_setopt(h, CURLOPT_WRITEDATA, &buf);
|
||||||
|
CURLcode rc = curl_easy_perform(h);
|
||||||
|
curl_easy_cleanup(h);
|
||||||
|
free(url);
|
||||||
|
if (rc != CURLE_OK) {
|
||||||
|
if (buf.d) free(buf.d);
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Value s = make_string(buf.d ? buf.d : "");
|
||||||
|
if (buf.d) free(buf.d);
|
||||||
|
push_value(vm, s);
|
||||||
|
#else
|
||||||
|
Value v = pop_value(vm); free_value(v);
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
41
src/vm/curl/post.c
Normal file
41
src/vm/curl/post.c
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
* libcurl POST builtin
|
||||||
|
*/
|
||||||
|
case OP_CURL_POST: {
|
||||||
|
#ifdef FUN_WITH_CURL
|
||||||
|
Value vbody = pop_value(vm);
|
||||||
|
Value vurl = pop_value(vm);
|
||||||
|
char *url = value_to_string_alloc(&vurl);
|
||||||
|
char *body = value_to_string_alloc(&vbody);
|
||||||
|
free_value(vurl);
|
||||||
|
free_value(vbody);
|
||||||
|
if (!url) { if (body) free(body); push_value(vm, make_string("")); break; }
|
||||||
|
if (!body) body = strdup("");
|
||||||
|
FunCurlBuf buf = { NULL, 0 };
|
||||||
|
CURL *h = curl_easy_init();
|
||||||
|
if (!h) { free(url); free(body); push_value(vm, make_string("")); break; }
|
||||||
|
curl_easy_setopt(h, CURLOPT_URL, url);
|
||||||
|
curl_easy_setopt(h, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
curl_easy_setopt(h, CURLOPT_POST, 1L);
|
||||||
|
curl_easy_setopt(h, CURLOPT_POSTFIELDS, body);
|
||||||
|
curl_easy_setopt(h, CURLOPT_WRITEFUNCTION, fun_curl_write_cb);
|
||||||
|
curl_easy_setopt(h, CURLOPT_WRITEDATA, &buf);
|
||||||
|
CURLcode rc = curl_easy_perform(h);
|
||||||
|
curl_easy_cleanup(h);
|
||||||
|
free(url);
|
||||||
|
free(body);
|
||||||
|
if (rc != CURLE_OK) {
|
||||||
|
if (buf.d) free(buf.d);
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Value s = make_string(buf.d ? buf.d : "");
|
||||||
|
if (buf.d) free(buf.d);
|
||||||
|
push_value(vm, s);
|
||||||
|
#else
|
||||||
|
Value a = pop_value(vm); free_value(a);
|
||||||
|
Value b = pop_value(vm); free_value(b);
|
||||||
|
push_value(vm, make_string(""));
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue