Wrap a C Function with Variable Length Argument List

200 views
Skip to first unread message

Steinway Wu

unread,
Jul 29, 2013, 2:26:25 PM7/29/13
to ats-lan...@googlegroups.com
How to wrap a C function with variable length argument list? 

I can see the "printf" example, using a flat tuple, and something like "types", together with some facilities written in C as indicated here:


I appreciate it a lot if someone could explain more details.

Thank you!

gmhwxi

unread,
Jul 29, 2013, 2:40:14 PM7/29/13
to ats-lan...@googlegroups.com
To do it in ATS is quite messy in ATS. I suggest not to do it. Instead, one can call C functions by
declaring extern functions in ATS.

In ATS2, one can use $extfcall to call functions in C directly. Though it is not type-safe, it is quite
convenient to do. E.g.,

val () = $extfcall (void, "printf", "c = %c and i = %i", 'a', 0)

Steinway Wu

unread,
Jul 29, 2013, 2:53:21 PM7/29/13
to ats-lan...@googlegroups.com
OK...But I can't do it this way, because I still need to ensure type safety for the first argument. Any alternatives?

gmhwxi

unread,
Jul 29, 2013, 3:00:37 PM7/29/13
to ats-lan...@googlegroups.com
If it is just for a printf-like function, it is done as follows:

extern
fun fprintf{ts:types} (out: FILEref, fmt: printf_c (ts), args: ts)

For instance, the format string:


"c = %c and i = %i"

is given the type printf_c ((char, int)); so the typechecker makes sure
that the args following is of the type (char, int).

What is the example you are trying to handle?

Steinway Wu

unread,
Jul 29, 2013, 3:15:36 PM7/29/13
to ats-lan...@googlegroups.com
It is redisCommand, which is a function used to issue command to redis server.

e.g.

redisCommand(redisCtx, "Some Command")
redisCommand(redisCtx, "Some Command with Arguments %s %s %d", "str1", "str2", 123)
redisCommand(redisCtx, "Some Command with Arguments %b %b", "hello", (size_t)5, "hi", (size_t)2)


gmhwxi

unread,
Jul 29, 2013, 3:34:17 PM7/29/13
to ats-lan...@googlegroups.com
This would be difficult as the typechecker needs to parse the format sting in order to do static typechecking.
One possibility is this:

abstype command (ts:types)

macdef foo = $extval (command(string::string::int::nil(), "foo")

val () = redisCommand (redisCtx, foo, @("str1", "str2", 123))

Steinway Wu

unread,
Jul 29, 2013, 3:41:45 PM7/29/13
to ats-lan...@googlegroups.com
OK, I will try this one, and come back later.

Thanks a lot.

Steinway Wu

unread,
Jul 29, 2013, 4:56:59 PM7/29/13
to ats-lan...@googlegroups.com
I am trying to do it in another way, but I got into another trouble.

What I am trying to do is to prepare a command in some function like

fun redis_command_prepare {ts: types} (fmt: printf_c (ts), args: ts): string = let
    val cmd = sprintf (fmt, args)
in
    string_of_strptr (cmd)
end

But it gives me type mismatch error

mismatch of static terms (tyleq):
The needed term is: S2Evararg(S2Evar(ts(2611)))
The actual term is: S2Eapp(S2Ecst(va_list_types_viewt0ype); S2Evar(ts(2611)))
exit(ATS): uncaught exception: ATS_2d0_2e2_2e10_2src_2ats_error_2esats__FatalErrorException(1027)

I've discussed this with Alex, but we can't figure it out. What do you think?

gmhwxi

unread,
Jul 29, 2013, 5:11:10 PM7/29/13
to ats-lan...@googlegroups.com
To implement variadic functions, you need libc/SATS/stdarg.sats.

In this case, you need vsprintf. Take a look at vsprintf in prelude/SATS/printf.sats

gmhwxi

unread,
Jul 29, 2013, 5:15:00 PM7/29/13
to ats-lan...@googlegroups.com
Maybe it is better to implement redis_command_prepare in C and then give it a type in ATS.
While it is possible to do it in ATS, it is quite involved and whatever gain you may get is quite limited.

Steinway Wu

unread,
Jul 29, 2013, 11:41:14 PM7/29/13
to ats-lan...@googlegroups.com
Hi, I come up with a working solution.

It seems that for most C libraries with variadic functions, they will provide two kinds of functions together.

1. redisCommand (redisContext *ctx, char *fmt, ...) //this is the ... form
2. redisvCommand (redisContext *ctx, char *fmt, va_list args) //this is the va_list form

And we can use the second form.

In ATS, we write this

fun ats_redis_command {ts: types} (ctx: !redis_ctx_ptr, fmt: string, args: ts): redis_reply_ptr = "mac#ats_redis_command_handler"

And embedded the following handler C code in ATS

#include <stdarg.h>
redisReply *ats_redis_command_handler (redisContext *ctx, char *fmt, ...) {
    va_list args;
    va_start (args, fmt);
    redisReply *reply = redisvCommand (ctx, fmt, args);
    va_end (args);
    return reply;
}

And it works.

Zhiqiang Ren

unread,
Jul 30, 2013, 11:36:57 AM7/30/13
to ats-lan...@googlegroups.com
But in this way, there's no type checking at all.

gmhwxi

unread,
Jul 30, 2013, 12:20:22 PM7/30/13
to ats-lan...@googlegroups.com
Try to introduce an abstract type

abstype format (ts:types) = string

fun redisCommand {ts: types} (ctx: !redis_ctx_ptr, fmt: format(ts), args: ts)

This at least shifts the burden to the user for creating a value of the type format(ts) for some ts. For instance,
one may do:

castfn format_unsafe {ts:types} (fmt: string): format(ts)

But it is possible that one has other ways to construct format-values.

Steinway Wu

unread,
Jul 30, 2013, 4:02:20 PM7/30/13
to ats-lan...@googlegroups.com
As I mentioned in our private talk, it's really not easy to type check the format string with all parameters, since they are not one-one mapping. I will try something else.

Brandon Barker

unread,
May 12, 2014, 8:13:32 PM5/12/14
to ats-lan...@googlegroups.com
Any updates on this topic? Primarily just curious about what the best way to call multityped c-variadic functions is, as I'm about to do a lot of it (e.g. scanf and fprintf - and am hoping the answer is not to create a separate function for each).

I don't see stdarg.sats anymore - any suggested examples?

Chris Double

unread,
May 12, 2014, 8:18:14 PM5/12/14
to ats-lan...@googlegroups.com
On Tue, May 13, 2014 at 12:13 PM, Brandon Barker
<brandon...@gmail.com> wrote:
> Any updates on this topic? Primarily just curious about what the best way to
> call multityped c-variadic functions is, as I'm about to do a lot of it
> (e.g. scanf and fprintf - and am hoping the answer is not to create a
> separate function for each).

I create a separate function but it's a bit of a pain. It'd be
wonderful if it was as easy as this Idris example:

<https://www.youtube.com/watch?v=fVBck2Zngjo>

--
http://www.bluishcoder.co.nz

gmhwxi

unread,
May 12, 2014, 10:06:11 PM5/12/14
to ats-lan...@googlegroups.com
I have not made any progress on this issue. Also, stdarg.sats
is yet to be supported in ATS2.

Handling variadic functions like printf is planned to be addressed as an issue of meta-programming.

For now, please call scanf and fprintf externally by using $extfcall. Scanf will be difficult to handled
anyway.

gmhwxi

unread,
May 12, 2014, 10:26:08 PM5/12/14
to ats-lan...@googlegroups.com, chris....@double.co.nz

Thanks for the link.

The approach is largely based on the one by Olivier Danvy.
Its limitation is well-known (e.g., it does not support non-static format strings).
Supporting something like printf ("%2.2d", ...) would be harder.

Also, supporting scanf would be much harder due to the need for error-handling.
Actually, printf also needs error-handling; supporting it in Idris, I think, can be a real
challenge.


On Monday, May 12, 2014 8:18:14 PM UTC-4, Chris Double wrote:
On Tue, May 13, 2014 at 12:13 PM, Brandon Barker
<brandon...@gmail.com> wrote:
> Any updates on this topic? Primarily just curious about what the best way to
> call multityped c-variadic functions is, as I'm about to do a lot of it
> (e.g. scanf and fprintf - and am hoping the answer is not to create a
> separate function for each).
github githwxi

Brandon Barker

unread,
May 12, 2014, 10:42:48 PM5/12/14
to gmhwxi, ats-lang-users, Chris Double
As to the first limitation, could this be handled by using a full-fledged tokenizer rather than a functional list only?

Brandon Barker
brandon...@gmail.com


--
You received this message because you are subscribed to the Google Groups "ats-lang-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ats-lang-users/c30f0c75-bfc0-4e0f-934c-c12daffd5114%40googlegroups.com.

gmhwxi

unread,
May 12, 2014, 10:47:54 PM5/12/14
to ats-lan...@googlegroups.com, gmhwxi, Chris Double
What do you mean by a full-fledged tokenizer?

Brandon Barker

unread,
May 13, 2014, 9:15:21 AM5/13/14
to gmhwxi, ats-lang-users, Chris Double

To construct the fields of the format datatype, a parser could ignore  everything between the '%' and the last encountered alphabetic character in the word. This seems too obvious, so I'm probably missing something.

gmhwxi

unread,
May 13, 2014, 10:22:35 AM5/13/14
to ats-lan...@googlegroups.com, gmhwxi, Chris Double
Well, the devil is always in the details.

Say you have parsed a format string like "%2.2f". What do you do next?

Steinway Wu

unread,
May 18, 2015, 1:40:35 PM5/18/15
to ats-lan...@googlegroups.com
Is there any updates on this topic? 

gmhwxi

unread,
May 18, 2015, 3:31:45 PM5/18/15
to ats-lan...@googlegroups.com
Not any that I am aware of.
Reply all
Reply to author
Forward
0 new messages