I am programming in C against a third party library (in HP/Mercury Loadrunner) that allows a varargs-style variable size argument list for one of it's functions. I want to call this function but I do not know up front how many arguments I will have.
There is a function made by one of my predecessors that serves somewhat but the problem here is that this function assumes the worst case scenario (over 3000 arguments) and hand-codes for that.
To illuminate, here's the (beginning of) the code. The function we call is web_submit_data()
. It will HTTP post a set of form data. This implementation came about when dealing with dynamically generated forms with an arbitrary number of fields.
(Cleaned up a fair bit from the original, which hand coded indexes by hand as well..)
web_submit_data_buffer_gazillion_items( const char *bufferName, const char *bufferValue)
{
const int size = 129;
int i = 0;
int j = 11;
web_submit_data(&bufferName[i++ * size], //"some form"
&bufferName[i++ * size], //"Action=https://blah.blah/form");
&bufferName[i++ * size], //"Method=POST");
&bufferName[i++ * size], //"TargetFrame=");
&bufferName[i++ * size], //"RecContentType=text/html");
&bufferName[i++ * size], //"Referer=https://blah.blah/index.html");
&bufferName[i++ * size], //"Snapshot=t1.inf");
&bufferName[i++ * size], //"Mode=HTML");
ITEMDATA, // missing in action: indexes 8 through 10
&bufferName[j * size],&bufferValue[j++ * size], ENDITEM,
&bufferName[j * size],&bufferValue[j++ * size], ENDITEM,
&bufferName[j * size],&bufferValue[j++ * size], ENDITEM,
..
(repeat the last 3 lines ad nauseum)
..
&bufferName[j * size],&bufferValue[j++ * size], ENDITEM,
&bufferName[j * size]);
}
Now I have found an external library that might work (http://www.dyncall.org) but I would much rather not a) be completely processor dependant and b) attempt to teach Loadrunner about linking in external sources..
Edit: The original function used hardcoded indexes instead of using a variable. Can still revert to that if it turns out to be too unpredictable. However, as I am unlikely to run this with a different compiler or hardware / OS I doubt that really is worth it.
Also: I don't have control over the implementation of web_submit_data(). So just pushing the problem down one level isn't going to cut it..
Another thing to note: The spec for web_submit_data()
uses a constant called LAST to mark the end of the argument list. The original implementation doesn't use it. Presumably the callsite does ..
In CamelBones I use libffi to call objc_msgSend(), which is a varargs function. Works a treat.
Variable length arguments are basically just a pointer to a bunch of packed data that is passed to the required function. It is the responsibility of the called function to interpret this packed data.
The architecture safe way to do this is to use the va_list macros (that n-alexander mentioned), otherwise you may run into issues with how various data types are padded in memory.
The proper way to design varargs functions is to actually have two versions, one that accepts the '...', which in turn extracts the va_list and passes it to a function that takes a va_list. This way you can dynamically construct the arguments if you need to and can instead call the va_list version of the function.
Most standard IO functions have varargs versions: vprintf for printf, vsprintf for sprintf... you get the idea. See if your library implements a function named "vweb_submit_data" or something to that effect. If they don't, email them and tell them to fix their library.
3000 lines of the same thing (even if it is preprocessor induced) makes me cringe
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With