Interfacing with C code that uses variadic argument list

Hi,

I’ve got plans for a new project where I’m using the functions from libcurl, so I’m getting to grips with the foreign system. It generally all seems quite straightforward but I wanted to ask about best practices when importing a function that has a variadic argument list.

The only function that’s given me a headache so far is curl_easy_setopt where the 3rd parameter is variadic.

My solution currently is to write a wrapper which modifies the way this function is imported based on the argument type:

callback :: #type proc(buffer: cstring, size: u64, nmemb: u64, userdata: rawptr) -> u64

my_curl_easy_setopt :: proc(handle: rawptr, opt: int, param: $T) {
  when T == callback {
    foreign curl {
      curl_easy_setopt :: proc(handle: rawptr, opt: int, param: callback) ---
    }
    curl_easy_setopt(handle, opt, param)
  }
  else {
    foreign curl {
      curl_easy_setopt :: proc(handle: rawptr, opt: int, param: rawptr) ---
    }
    curl_easy_setopt(handle, opt, param)
  }
}

Is this the best approach? I don’t think I’ve seen any samples which do this.

I’ve created a github gist with complete sample code: Odin code that imports libcurl functions · GitHub

foreign curl {
      curl_easy_setopt :: proc(handle: rawptr, opt: c.int, #c_vararg args: ..any) -> c.int---
}

Aha thanks for the response - I knew I must have missed something!

I just want to point out, that you have to pay attention as to how you pass your arguments. For example if you pass a string literal (e.g. "Hello World") you need to specifically cast it to cstring (e.g. cstring("Hello World")) otherwise it will be passed as an odin string and the program will most likely segfault.

Thanks for the tip.

My approach to this had been to “manually” allocate memory with zero terminator e.g.

s := "www.google.com"
c_str := make([]u8, len(s) + 1)
defer delete(c_str)

copy(c_str, s)

curl_easy_setopt(handle, 10000 + 2, &c_str[0])

but obviously it’s a lot cleaner if I can just cast to a cstring (or use strings.clone_to_cstring).

I’ve cleaned up the gist I posted originally with what I’ve learned.

You should be fine with just

c_str : cstring = "www.google.com"