doptimusprime
doptimusprime

Reputation: 9415

_vscwprintf on Mac OS X/Linux

I am porting an application on Mac OS X which was written for Windows.

In this application, there are many instances of _vscwprintf and _vscprintf.

This question helped me to implement _vsprintf on Mac OS X. But same technique for _vswprintf is not working.

Can anyone give the alternative of _vscwprintf on Mac OS X? Or there any equivalent method for this?

Upvotes: 2

Views: 3741

Answers (2)

Andrey Belykh
Andrey Belykh

Reputation: 2654

I recommend using open_wmemstream instead. Something like that:

#include <stdio.h>
#include <string>
#include <stdarg.h> 

using namespace std;

wstring wstring_format(const wchar_t* format, ...)
{
    wchar_t* buf;
    size_t size;
    FILE* stream = open_wmemstream(&buf, &size);

    va_list args;
    va_start(args, format);
    vfwprintf(stream, format, args);
    va_end(args);

    fclose(stream);
    wstring result(buf, buf + size);
    free(buf);

    return result;
}

Upvotes: 1

Jonathan Leffler
Jonathan Leffler

Reputation: 754540

Microsoft describes the functions as returning the number of characters that would be used if the string were formatted — note that they are documented as not including the null terminator.

int _vscprintf(
   const char *format,
   va_list argptr 
);
int _vscwprintf(
   const wchar_t *format,
   va_list argptr 
);

Initial answer

These functions can, therefore, be emulated with vsprintf() and vswprintf():

int _vscprintf(const char *format, va_list argptr)
{
    return(vsnprintf(0, 0, format, argptr));
}

int _vscwprintf(const wchar_t *format, va_list argptr)
{
    return(vswprintf(0, 0, format, argptr));
}

It is up to you whether you remove the leading underscore; I would.

Note that the _vscwprintf() implementation above is flawed; see the code below.


vscprintf() and scprintf()

Apologies: I wrote vsprintf() where I needed to write vsnprintf() (now fixed in the code above); however, vswprintf() already has the safer interface with the buffer length, so there is no vsnwprintf(). There's a reason I prefer to test compile code before (or shortly after) posting it — it's been irksome not having the wherewithal to do so for a couple of days.

Here's an SSCCE for vscprintf() (and scprintf()):

#include <stdio.h>
#include <stdarg.h>

extern int vscprintf(const char *format, va_list argptr);
extern int scprintf(const char *format, ...);

int vscprintf(const char *format, va_list argptr)
{
    return(vsnprintf(0, 0, format, argptr));
}

int scprintf(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    int rc = vscprintf(format, args);
    va_end(args);
    return rc;
}

int main(void)
{
    int l = scprintf("%-8s %8d\n", "abc", 123);
    if (l > 0)
    {
        char buffer[l+1];
        int n = snprintf(buffer, sizeof(buffer), "%-8s %8d\n", "abc", 123);
        printf("%d = %d: %s", l, n, buffer);
    }
    return 0;
}

Output:

18 = 18: abc           123

vscwprintf() and scwprintf()

It turns out to be harder to simulate _vscwprintf() because the vswprintf() function is not as helpful as the vsnprintf() function. Specifically, vswprintf() reports an error if the formatted string won't fit in the formatted space, whereas vsnprintf() reports the number of characters that would have been needed in the buffer if it was going to fit. Hence, you have to work by trial and error:

#include <stdio.h>
#include <stdarg.h>
#include <wchar.h>

extern int vscwprintf(const wchar_t *format, va_list argptr);
extern int scwprintf(const wchar_t *format, ...);

int vscwprintf(const wchar_t *format, va_list argptr)
{
    // Unlike vsnprintf(), vswprintf() does not tell you how many
    // characters would have been written if there was space enough in
    // the buffer - it just reports an error when there is not enough
    // space.  Assume a moderately large machine so kilobytes of wchar_t
    // on the stack is not a problem.
    int buf_size = 1024;
    while (buf_size < 1024 * 1024)
    {
        va_list args;
        va_copy(args, argptr);
        wchar_t buffer[buf_size];
        int fmt_size = vswprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), format, args);
        if (fmt_size >= 0)
            return fmt_size;
        buf_size *= 2;
    }
    return -1;
}

int scwprintf(const wchar_t *format, ...)
{
    va_list args;
    va_start(args, format);
    int rc = vscwprintf(format, args);
    va_end(args);
    return rc;
}

int main(void)
{
    int l = scwprintf(L"%-8ls %8d\n", L"abc", 123);
    if (l > 0)
    {
        wchar_t buffer[l+1];
        int n = swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), L"%-8ls %8d\n", L"abc", 123);
        wprintf(L"%d = %d: %ls", l, n, buffer);
    }
    return 0;
}

When run, this produces the output

18 = 18: abc           123

(the same as before).

Tested on Mac OS X 10.8.3 using GCC 4.7.3 (which was built on Mac OS X 10.7.5, but that shouldn't cause any problems).

Upvotes: 6

Related Questions