From 36a705474c8e27f2cf2a589d00c1bf92bf3a267c Mon Sep 17 00:00:00 2001 From: Josh Watzman Date: Tue, 3 Aug 2010 21:18:34 -0700 Subject: [PATCH] Add curl MLton FFI bindings Getting the data at a URL can be a useful thing to do. The best way to do it is probably with libcurl bindings. This unfortunately requires a small C wrapper to do some bookkeeping (curl only wants to write via a function pointer or a FILE*) but it's still pretty braindead. --- curl/README | 5 ++++ curl/curl.mlb | 9 +++++++ curl/curl.sig | 3 +++ curl/curl.sml | 31 +++++++++++++++++++++++ curl/curl_supereasy.c | 59 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+) create mode 100644 curl/README create mode 100644 curl/curl.mlb create mode 100644 curl/curl.sig create mode 100644 curl/curl.sml create mode 100644 curl/curl_supereasy.c diff --git a/curl/README b/curl/README new file mode 100644 index 0000000..2fa483a --- /dev/null +++ b/curl/README @@ -0,0 +1,5 @@ +This attempts to be a very simple interface to libcurl. Pass in your URL, get the data at that URL back. + +Because MLton's build system is half-assed, in order to use this lib you must: + - add "-link-opt -lcurl" to your mlton command line parameters + - add ".../stilts/curl/curl_supereasy.c" after your mlb file on the mlton command line diff --git a/curl/curl.mlb b/curl/curl.mlb new file mode 100644 index 0000000..c42513f --- /dev/null +++ b/curl/curl.mlb @@ -0,0 +1,9 @@ +ann + "allowFFI true" +in + $(SML_LIB)/basis/basis.mlb + $(SML_LIB)/basis/mlton.mlb + $(SML_LIB)/basis/c-types.mlb + curl.sig + curl.sml +end diff --git a/curl/curl.sig b/curl/curl.sig new file mode 100644 index 0000000..eeafc7f --- /dev/null +++ b/curl/curl.sig @@ -0,0 +1,3 @@ +signature CURL = sig + val curl : string -> string +end diff --git a/curl/curl.sml b/curl/curl.sml new file mode 100644 index 0000000..3c8242c --- /dev/null +++ b/curl/curl.sml @@ -0,0 +1,31 @@ +structure Curl :> CURL = struct + + type ptr = MLton.Pointer.t + + fun read_bytes (p, n) = + Word8Vector.tabulate (n, fn i => MLton.Pointer.getWord8 (p, i)) + + fun curl url = + let + val p = + (_import "curl_supereasy" : string -> ptr;) + (url) + + val len = + (_import "curl_supereasy_len" : ptr -> int;) + (p) + + val data = + (_import "curl_supereasy_data" : ptr -> ptr;) + (p) + + val ret = Byte.bytesToString (read_bytes (data, len)) + + val _ = + (_import "curl_supereasy_cleanup" : ptr -> unit;) + (p) + in + ret + end + +end diff --git a/curl/curl_supereasy.c b/curl/curl_supereasy.c new file mode 100644 index 0000000..47760b1 --- /dev/null +++ b/curl/curl_supereasy.c @@ -0,0 +1,59 @@ +#include +#include +#include + +typedef struct +{ + char *data; + size_t len; +} +curl_supereasy_data_t; + +size_t curl_supereasy_callback( + void *buffer, + size_t size, + size_t nmemb, + curl_supereasy_data_t *datat) +{ + size_t old_len = datat->len; + size_t additional_len = size*nmemb; + + datat->data = realloc(datat->data, old_len + additional_len); + datat->len = old_len + additional_len; + + memcpy(datat->data + old_len, buffer, additional_len); + + return additional_len; +} + +curl_supereasy_data_t* curl_supereasy(char *url) +{ + curl_supereasy_data_t *datat = malloc(sizeof(curl_supereasy_data_t)); + datat->data = NULL; + datat->len = 0; + + CURL *curl = curl_easy_init(); + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_supereasy_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, datat); + curl_easy_perform(curl); + curl_easy_cleanup(curl); + + return datat; +} + +char* curl_supereasy_data(curl_supereasy_data_t *datat) +{ + return datat->data; +} + +size_t curl_supereasy_len(curl_supereasy_data_t *datat) +{ + return datat->len; +} + +void curl_supereasy_cleanup(curl_supereasy_data_t *datat) +{ + free(datat->data); + free(datat); +}