ext
ext

Reputation: 2903

Replacement for vsscanf on msvc

I've run into an issue porting a codebase from linux (gcc) to windows (msvc). It seems like the C99 function vsscanf isn't available and has no obvious replacement.

I've read about a solution using the internal function _input_l and linking statically to the crt runtime, but unfortunately I cannot link statically since it would mess with all the plugins (as dlls) being loaded by the application.

So is there any replacement or a way to write a wrapper for vsscanf?

Update 2016-02-24:

When this was first asked there was no native replacement but since then MSVC has implemented support for this and much more.

Upvotes: 4

Views: 2627

Answers (6)

Naskel
Naskel

Reputation: 1

modified from : http://www.gamedev.net/topic/310888-no-vfscanf-in-visual-studio/

#if defined(_WIN32) && (_MSC_VER <= 1500)
static int vsscanf(
    const char  *buffer,
    const char  *format,
    va_list     argPtr
)
{
    // Get an upper bound for the # of args
    size_t count = 0;
    const char* p = format;
    while(1)
    {
        char c = *(p++);
        if (c == 0) 
            break;
        if (c == '%' && (p[0] != '*' && p[0] != '%')) 
            ++count;
    }
    if (count <= 0)
        return 0;
    int result;
    // copy stack pointer
    _asm
    {
        mov esi, esp;
    }
    // push variable parameters pointers on stack
    for (int i = count - 1; i >= 0; --i)
    {
        _asm
        {
            mov eax, dword ptr[i];
            mov ecx, dword ptr [argPtr];
            mov edx, dword ptr [ecx+eax*4];
            push edx;
        }
    }
    int stackAdvance = (2 + count) * 4;
    _asm
    {
        // now push on the fixed params
        mov eax, dword ptr [format];
        push eax;
        mov eax, dword ptr [buffer];
        push eax;
        // call sscanf, and more the result in to result
        call dword ptr [sscanf];
        mov result, eax;
        // restore stack pointer
        mov eax, dword ptr[stackAdvance];
        add esp, eax;
    }
    return result;
}
#endif // _WIN32 / _MSC_VER <= 1500

tested only on Visual Studio 2008

Upvotes: 0

Frahm
Frahm

Reputation: 815

if you want to wrap sscanf and you are using C++11, you can do this:

template<typename... Args>
int mysscanf(const char* str, const char* fmt, Args... args) {
  //...
  return sscanf(str, fmt, args...);
}

to make this work on msvc, you need to download this update:

http://www.microsoft.com/en-us/download/details.aspx?id=35515

Upvotes: 0

Alan Carre
Alan Carre

Reputation: 11

Funny it never came up for me before today. I could've sworn I'd used the function in the past. But anyway, here's a solution that works and is as safe as your arguments and format string:

template < size_t _NumArgs >

int VSSCANF_S(LPCTSTR strSrc, LPCTSTR ptcFmt, INT_PTR (&arr)[_NumArgs]) {

class vaArgs
      {
      vaArgs() {}
      INT_PTR* m_args[_NumArgs];
      public:
         vaArgs(INT_PTR (&arr)[_NumArgs])
                {
                for(size_t nIndex=0;nIndex<_NumArgs;++nIndex)
                    m_args[nIndex] = &arr[nIndex];
                }
      };

   return sscanf_s(strSrc, ptcFmt, vaArgs(arr));
   }

///////////////////////////////////////////////////////////////////////////////

int _tmain(int, LPCTSTR argv[])

{
INT_PTR args[3];
int nScanned = VSSCANF_S(_T("-52 Hello 456 @"), _T("%d Hello %u %c"), args);

return printf(_T("Arg1 = %d, arg2 = %u, arg3 = %c\n"), args[0], args[1], args[2]);
}

Out:

Arg1 = -52, arg2 = 456, arg3 = @ Press any key to continue . . .

Well I can't get the formatting right but you get the idea.

Upvotes: 0

Mark B
Mark B

Reputation: 96301

As this is tagged C++ have you considered just biting the bullet and moving away from the scanf line of functions completely? The C++ idiomatic way would be to use a std::istringstream. Rewriting to make use of that instead of looking for a vsscanf replacement would possibly be easier and more portable, not to mention having much greater type safety.

Upvotes: 0

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215547

A hack that should work:

int vsscanf(const char *s, const char *fmt, va_list ap)
{
  void *a[20];
  int i;
  for (i=0; i<sizeof(a)/sizeof(a[0]); i++) a[i] = va_arg(ap, void *);
  return sscanf(s, fmt, a[0], a[1], a[2], a[3], a[4], a[5], a[6], /* etc... */);
}

Replace 20 with the max number of args you think you might need. This code isn't terribly portable but it's only intended to be used on one particular broken system missing vsscanf so that shouldn't matter so much.

Upvotes: 3

Fredrik Ullner
Fredrik Ullner

Reputation: 2166

A quick search turned up several suggestions, including http://www.flipcode.net/archives/vsscanf_for_Win32.shtml

Upvotes: 0

Related Questions