Doing http requests with gforth and libcurl
Forth is great
Forth is great. Unfortunately most of my colleagues are completely unaware of it or at best think of it as something alien for embedded systems.
I love it, beside of its simplicity and its cleanness, it gives me the feeling of having full power over my system, like in the 8bit ara. Hint: read Jones forth - it is an eye opener! You'll understand forth as a system, not only as a programming languange.
Gforths ffi
There are many different forth-implementation, native (running on a bare metal machine / board) or hosted forth. I like gforth. Some forth enthusiasts call it bloated. Really impressive is its ffi (foreign function interface), which even makes c-callbacks very easy. Coming from common lisp, and it's various ffi's, I was very impressed.
Currently I am coming back to forth, because of programing my wonderful picocalc in zeptoforth.
Simple libcurl bindings for gforth
Following as an example, my very simple implementation of bindings of libcurl to make http requests. I am far from being an forth expert. Actually it was quite a challenge for me to do a simple http-request out of gforth, because I nearly found no example code. How do c-callbacks work, etc?
That's also the reason for me publishing this code, hopefully someone is happy to find this information. Take it with a grain of salt, as mentioned, I am no forth expert.
Make sure, that f.e. libcurl-gnutls is on your system. Code was testet at AMD64 Archlinux and AARCH64 Debian.
\ http-request bindings to libcurl for gforth (>= 0.7.9) c-library curl s" curl-gnutls" add-lib \c #include <curl/curl.h> \c #include <curl/easy.h> c-value curl-global-all CURL_GLOBAL_ALL -- n c-value curle-ok CURLE_OK -- n c-value curlopt-url CURLOPT_URL -- n c-value curlopt-customrequest CURLOPT_CUSTOMREQUEST -- n c-value curlopt-writefunction CURLOPT_WRITEFUNCTION -- n c-value curlopt-writedata CURLOPT_WRITEDATA -- n c-value curlopt-useragent CURLOPT_USERAGENT -- n c-value curlinfo-response-code CURLINFO_RESPONSE_CODE -- n c-function curl-global-init curl_global_init n -- void c-function curl-easy-init curl_easy_init void -- a c-function curl-easy-setopt curl_easy_setopt a n a -- void c-function curl-easy-perform curl_easy_perform a -- a c-function curl-easy-getinfo curl_easy_getinfo a n a -- void c-function curl-easy-cleanup curl_easy_cleanup a -- void c-callback make-receive-request a n n a -- n end-c-library : receive-request ( data chunksize nmemb usrptr ) -rot * swap over >r $+! r> ; ' receive-request make-receive-request constant recv : >cstring ( addr u -- c-string-addr ) [ s\" \0" ] 2literal s+ drop ; s" GET" >cstring constant method-get s" POST" >cstring constant method-post s" PUT" >cstring constant method-put s" DELETE" >cstring constant method-delete s" PATCH" >cstring constant method-patch variable curl-data variable response-code : http-request ( method url-addr url-len -- status content-addr content-len ) curl-data $init curl-global-all curl-global-init curl-easy-init { curl } curl 0= if ." CURL initialization failed..." quit then >cstring curl curlopt-url rot curl-easy-setopt curl curlopt-customrequest rot curl-easy-setopt curl curlopt-writefunction recv curl-easy-setopt curl curlopt-writedata curl-data curl-easy-setopt curl curl-easy-perform curle-ok <> if ." CURL perform failed..." quit then curl curlinfo-response-code response-code curl-easy-getinfo curl curl-easy-cleanup response-code @ curl-data $@ save-mem curl-data $free ; \ you'll have to make sure, to free memory on your own! : my-example ( -- ) method-get s" https://example.com" http-request 2dup type drop free ;