vsprintf

Linux specific forum
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

vsprintf

Post 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 ?
guy rabiller | radfac founder / ceo | raafal.org
Fred
Administrator
Administrator
Posts: 18207
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: vsprintf

Post 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
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

Re: vsprintf

Post by grabiller »

That does not answer my question :wink:

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 ?
guy rabiller | radfac founder / ceo | raafal.org
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: vsprintf

Post by wilbert »

You get the error because what your are passing is not a va_list .
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

Re: vsprintf

Post 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:

Code: Select all

Prototype MyCallback( *s, *args )
But then ? What to do with *args ?

On Windows it's trivial, but on Linux/Mac ? Is this simply possible ?
guy rabiller | radfac founder / ceo | raafal.org
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: vsprintf

Post 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 ?
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

Re: vsprintf

Post 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.
guy rabiller | radfac founder / ceo | raafal.org
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: vsprintf

Post 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.
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

Re: vsprintf

Post 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.
guy rabiller | radfac founder / ceo | raafal.org
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

Re: vsprintf

Post 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..
guy rabiller | radfac founder / ceo | raafal.org
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: vsprintf

Post 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.
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

Re: vsprintf

Post 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.
guy rabiller | radfac founder / ceo | raafal.org
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: vsprintf

Post by wilbert »

If you can do it manually, that sounds like a good idea.
Rest operators are not that easy to work with.
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

Re: vsprintf

Post 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 :wink:
guy rabiller | radfac founder / ceo | raafal.org
Post Reply