Page 1 of 1
vsprintf
Posted: Mon Oct 08, 2012 12:33 pm
by grabiller
Hi,
I'm using this code on Windows to import and test vsprintf (and vsnprintf):
Code: Select all
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
ImportC "user32.lib"
vsprintf.i( *buffer.i, format.p-ascii, *argptr )
_vsnprintf.i( *buffer.i, count.i, format.p-ascii, *argptr )
CompilerCase #PB_OS_Linux
ImportC ""
vsprintf.i( *buffer.i, format.p-ascii, *argptr )
vsnprintf.i( *buffer.i, count.i, format.p-ascii, *argptr )
CompilerCase #PB_OS_MacOS
ImportC ""
vsprintf.i( *buffer.i, format.p-ascii, *argptr )
vsnprintf.i( *buffer.i, count.i, format.p-ascii, *argptr )
CompilerEndSelect
EndImport
Define buffer.s = Space(1024)
Define value.l = 23
Debug vsprintf( @buffer, "Hi I'm %ld years old", @value )
Debug buffer
This works perfectly well on Windows but on Linux (and Mac) I get a:
"[ERROR] Invalid Memory Access"
on the line:
Debug vsprintf( @buffer, "Hi I'm %ld years old", @value )
Any idea why this would happen on Linux/Mac and not on Windows ?
I don't have a linker error so I suppose the vsprintf function is properly imported ?
Re: vsprintf
Posted: Mon Oct 08, 2012 12:39 pm
by Fred
You shouldn't use this command, it doesn't support unicode and even in C, it's not advised to use it. There is some code on the forum to support pattern replace which should do the trick:
http://www.purebasic.fr/english/viewtop ... it=sprintf
Re: vsprintf
Posted: Mon Oct 08, 2012 12:48 pm
by grabiller
That does not answer my question
vsprintf is not advised to be used, but vsnprintf is, as this is the 'safe' version, and I'm planning to use vsnprintf actualy.
But I was testing both just to be sure it imports and works correctly.
I don't need unicode as this is just for a callback receiving ascii string (or utf8 string but I'll change the pseudotype later).
So any idea why would this works on Windows and give me a "Invalid Memory Access" on Linux/Mac ?
Re: vsprintf
Posted: Mon Oct 08, 2012 1:04 pm
by wilbert
You get the error because what your are passing is not a va_list .
Re: vsprintf
Posted: Mon Oct 08, 2012 2:03 pm
by grabiller
I got it, on Linux/Mac va_list is a structure..
Ok so what do you guys do/use when using a library, from PB, which ask for a callback with the following signature:
Code: Select all
void MyCallback( const char* s, ... )
I can provide a procedure with such PB Signature:
But then ? What to do with *args ?
On Windows it's trivial, but on Linux/Mac ? Is this simply possible ?
Re: vsprintf
Posted: Mon Oct 08, 2012 2:15 pm
by wilbert
The rest operator ... doesn't indicate an array.
It indicates that a variable number of arguments will follow.
A few questions
- do you know the minimum and maximum number of arguments your procedure will get ?
- are you using x86 or x64 ?
Re: vsprintf
Posted: Mon Oct 08, 2012 2:27 pm
by grabiller
Unfortunately I don't know the min/max number of arguments in advance as Squirrel is asking to provide a callback to handle the built-in script print() function through his api function:
Code: Select all
void sq_setprintfunc( HSQUIRRELVM v, SQPRINTFUNCTION printfunc, SQPRINTFUNCTION errorfunc );
Both printfunc and errorfunc must have the following signature:
Code: Select all
void printfunc( HSQUIRRELVM v, const SQChar *s, ... );
I'm using x64 only on Linux/Mac.
Re: vsprintf
Posted: Mon Oct 08, 2012 2:39 pm
by wilbert
So ...
- The first argument ( HSQUIRRELVM v ) is something you don't need to use and the other arguments are like printf.
- You want to forward the call to a printf variant that outputs a string so you can further process it inside the procedure using PureBasic commands.
Is this correct ?
If so, forwarding the call should probably be possible using some inline asm.
Re: vsprintf
Posted: Mon Oct 08, 2012 3:06 pm
by grabiller
Yes, ideally I would like to forward the call to snprintf (providing a buffer and its size) and then use the string result for logging purpose.
Re: vsprintf
Posted: Mon Oct 08, 2012 3:15 pm
by grabiller
Hmm.. thinking about it, if I just forward directly the call to snprintf (by importing it instead of vsnprintf) with the pointer I get from the callback, it may work directly.. stupid me..
Let me check..
Re: vsprintf
Posted: Mon Oct 08, 2012 4:13 pm
by wilbert
I would go for asprintf / free and use PeekS with #PB_Ascii to get the string.
I was thinking about something like this
Code: Select all
Global *str, ret_addr
Procedure PrintFunction(*s)
Protected TmpStr.s = PeekS(*s, -1, #PB_Ascii)
MessageRequester("", TmpStr)
EndProcedure
Procedure Addr_PrintFunc()
ProcedureReturn ?print_func_start
print_func_start:
!pop qword [v_ret_addr] ; save original return address
!mov rdi, [p_str] ; replace first argument with *str
!extern _asprintf ; call asprintf
!call _asprintf
PrintFunction(*str) ; call PrintFunction
!mov rdi, [p_str]
!extern _free ; free *str
!call _free
!push qword [v_ret_addr] ; put original return address back
!ret
EndProcedure
but I have no idea if it would work.
If it works, it only does so for Linux and OS X and it also is not thread safe unfortunately.
Addr_PrintFunc() would return the address you need to pass as the address of the callback.
Re: vsprintf
Posted: Mon Oct 08, 2012 7:27 pm
by grabiller
Nope, no luck : -/
I'm trying to solve this problem differently by.. not using callbacks relying on the rest operator.
Fortunately Squirrel provide hooks to 'manually' handle runtime and compile time errors by querying its stack directly, so I'll go this way for now. It's more work but at least I'll be on solid ground. I hope I won't stumble later on libs which do not provide alternative ways..
Perhaps it could be a good idea to include some PureBasic functions to deal with callbacks involving rest operator. Perhaps a pseudotype or something.
Re: vsprintf
Posted: Mon Oct 08, 2012 7:55 pm
by wilbert
If you can do it manually, that sounds like a good idea.
Rest operators are not that easy to work with.
Re: vsprintf
Posted: Tue Oct 09, 2012 12:32 am
by grabiller
Indeed.
Perhaps it's not a good idea for libraries to rely on callbacks with rest operators, they should better provide vectorized callbacks as well
