On Sat, Jun 30, 2012 at 12:21 AM, Bernd <prof7...@gmail.com> wrote: > Hello, I need to call the following function: > > > /** > * Notifies Purple that a buddy's status has been activated. > * > * This is meant to be called from protocol plugins. > * > * @param account The account the user is on. > * @param name The name of the buddy. > * @param status_id The status ID. > * @param ... A NULL-terminated list of attribute IDs and values, > * beginning with the value for @a attr_id. > */ > void purple_prpl_got_user_status(PurpleAccount *account, const char *name, > const char > *status_id, ...) G_GNUC_NULL_TERMINATED; > > > I have translated it as follows: > > procedure purple_prpl_got_user_status(account: PPurpleAccount; > name_, status_id: PChar; par3: array of const); cdecl; external LIBPURPLE;
That would be: procedure purple_prpl_got_user_status(account: PPurpleAccount; name_, status_id: PChar); varargs; cdecl; external LIBPURPLE; "varargs" is a compiler directive that reflects the ellipsis "..." in C. It is only valid in external function declarations for static linking (as in your case) or function prototypes for dynamic linking using LoadLibrary()/GetProcAddress(). It is always combined with cdecl (read on) and you cannot implement a varargs cdecl function (you get a compiler error if you try), only declare a prototype and link to an external one written in C. I am not 100% sure FPC supports the varargs directive but I've found at least one varargs cdecl function (gtk_tree_path_new_from_indices in gtk2extrah.inc), so it probably does. > How is this such a list of arguments actually implemented? is it on > the stack? What structure does it have? Can I somehow manually put > stuff onto the stack to make it think it is an empty list? maybe pass > another integer and pass 0 instead of this list? I am no C programmer but as I understand it the caller can pass as many variable parameters of any type (actually it has to pass what the function expects it to). The parameters are pushed into the stack after fixed parameters and the callee (function) will retrieve them out of the stack with pointer arithmetic using the address past the end of the last fixed parameter (in your case status_id) as a starting point and increment the running pointer according to every expected variable parameter's type size. So the number and type of the variable parameters must be known and respected by both caller and function and is usually deduced by the values of the fixed parameters. A well known such function with variable parameters is printf() where the type and number of variable parameters is deduced by the placeholders in the format string passed as the fixed parameter. In your case I think that the value of the status_id parameter dictates the number and type of the extra parameters. You'll have to read the documentation of the function. Stack cleanup is possible although the parameter stack has an unknown size at compile time because of the cdecl calling convention where the caller must allocate AND cleanup the stack and the caller knows the number and types of the variable params at compile-time, the function doesn't. In other calling conventions where the caller allocates the stack but the function has to clean it up (e.g. pascal/stdcall) the ellipsis/varargs cannot work. A pascal open array of const which is the closest concept to a C ellipsis may have similar semantics but its binary representation on the parameter stack is completely different. First of all, since it has to work in all calling conventions and not just cdecl the high bound of passed array elements is pushed in the stack after a pointer to an array of TVarRec structures that each contains a type attribute and either a value or a pointer to the value of the parameter. So the open array doesn't need to be the last parameter like the C ellipsis and there can be more than one in a routine signature. So your declaration of purple_prpl_got_user_status procedure purple_prpl_got_user_status(account: PPurpleAccount; name_, status_id: PChar; par3: array of const); is equivalent to: procedure purple_prpl_got_user_status(account: PPurpleAccount; name_, status_id: PChar; par3: PVarRecArray; par3HighBound: Integer); So the caller pushes only a pointer to a TVarRec array and an integer while the function expects a continuous "stream" of parameters. If you pass [] the compiler generates code to push a nil pointer (zero PtrInt) and a high bound of -1. If the C function can handle these values on the stack it *sort of* works by accident, but it will probably fail if it tries to read past the -1 high bound for a specific value of status_id that requires more variable parameters. For details on open array parameters read this article: http://rvelthuis.de/articles/articles-openarr.html (Disclaimer: the description of open arrays apply to Delphi but my guess is that the implementation in FPC is similar). HTH Constantine. _______________________________________________ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal