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
|
|
@ -145,6 +145,9 @@ static const char *opcode_name(OpCode op) {
|
|||
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_PCSC_ESTABLISH: return "PCSC_ESTABLISH";
|
||||
case OP_PCSC_RELEASE: return "PCSC_RELEASE";
|
||||
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_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
|
||||
OP_PCSC_ESTABLISH, // returns context id (>0) or 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);
|
||||
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 */
|
||||
if (strcmp(name, "pcsc_establish") == 0) {
|
||||
(*pos)++; /* '(' */
|
||||
|
|
|
|||
24
src/vm.c
24
src/vm.c
|
|
@ -32,6 +32,25 @@
|
|||
#include <pcre2.h>
|
||||
#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 */
|
||||
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);
|
||||
|
|
@ -679,6 +698,11 @@ void vm_run(VM *vm, Bytecode *entry) {
|
|||
#include "vm/json/from_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 */
|
||||
#include "vm/pcre2/test.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",
|
||||
"BAND","BOR","BXOR","BNOT","SHL","SHR","ROTL","ROTR",
|
||||
"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",
|
||||
"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",
|
||||
|
|
|
|||
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