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?
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).
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;
}
Related
From what I have read, this function should work, but for the life of me, I cannot figure out why it isn't.
I override the invalid parameter handler so I can continue running if an invalid parameter is passed (such as a buffer that is too small).
asprintf_s macro takes the parameters of a standard sprintf_s, adds the filename and line number, then calls asprintf_s2. It checks to see if the result would have overflowed the buffer, prints the filename and the line of where the overflowed occurred.
Problem: I'm guessing I'm doing something wrong with the variadic parameters as it always returns an overflow.
Output of program below
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <string>
#include <excpt.h>
#include <stdarg.h>
#define asprintf_s(...) asprintf_s2( __FILE__, __LINE__, __VA_ARGS__)
//#define asprintf_s(...) sprintf_s( __VA_ARGS__ )
inline int asprintf_s2(char *file, int line, char *dest, int sizeOfDest, char *Format, ...)
{
va_list pArgs;
va_start(pArgs, Format);
int sizeOfBuffer = sprintf_s(dest, sizeOfDest, Format, pArgs);
if (sizeOfBuffer == -1) printf("Buffer Overflow! File: %s LINE: %d\n", file, line );
va_end(pArgs);
return sizeOfBuffer;
}
void in_house_invalid_parameter(
const wchar_t * expression,
const wchar_t * function,
const wchar_t * file,
unsigned int line,
uintptr_t pReserved
)
{
// Do nothing on invalid parameter
}
int main()
{
char temp1[3];
char temp80[80];
std::string input;
int k = -3;
_set_invalid_parameter_handler(in_house_invalid_parameter);
strcpy_s(temp1, sizeof(temp1), "XX");
strcpy_s(temp80, sizeof(temp80), "1");
printf("Temp1:'%s'\n", temp1);
k = asprintf_s(temp1, sizeof(temp1), "%s\n", temp80);
printf("k:%d temp1:'%s', temp80:'%s'\n", k, temp1, temp80);
std::getline(std::cin, input);
return 0;
}
You just have to use vsprintf or vsprintf_s function
Edit: or vasprintf for your case
I have the following code to append a buffer using vsnprintf().
#include <stdio.h>
#include <stdarg.h>
using namespace std;
void MyPrintFunc(char *buffer, size_t sizeOfBuffer, const char* format, ...)
{
va_list arg;
va_start(arg, format);
vsnprintf(buffer, sizeOfBuffer, format, arg);
va_end(arg);
}
int main()
{
char buffer[1000] = { 0 };
const char* abc = "abc";
const char* def = "def";
MyPrintFunc(buffer, 1000, "%s", abc);
MyPrintFunc(buffer, 1000, "%s%s", buffer, def);
printf("%s\n", buffer);
return 0;
}
It gave different output on both Windows and Linux.
On Windows (using msvc-14.0 compiler), it give desired output of abcdef.
But on Linux (using gcc-5.4), it only print output of def.
How can I get the correct output?
Don't use the same buffer as both an output and input to vsnprintf.
Thanks everyone for the input.
My solution to this is to create a copy of the buffer if user of the MyPrintFunc() used it to append buffer:
void MyPrintFunc(char *buffer, size_t sizeOfBuffer, const char* format, ...)
{
va_list arg;
va_list arg_copy;
va_start(arg, format);
va_copy(arg_copy, arg);
if (buffer == va_arg(arg, char*))
{
char temp[strlen(buffer)];
strcpy(temp, buffer);
MyPrintFunc(buffer, sizeOfBuffer, format, temp, va_arg(arg,char*));
}
else
{
vsnprintf(buffer, sizeOfBuffer, format, arg_copy);
}
va_end(arg);
va_end(arg_copy);
}
I need to translate, vswscanf function from c to c++
using wide string stream and var arg,
can you help me ?
#include <stdarg.h>
#include <wchar.h>
void GetWideMatches ( const wchar_t * str, const wchar_t * format, ... )
{
va_list args;
va_start (args, format);
vswscanf (str, format, args);
va_end (args);
}
int main ()
{
int val;
wchar_t buf[100];
GetWideMatches ( L"99 bottles of beer on the wall", L" %d %ls ", &val, buf);
wprintf (L"Product: %ls\nQuantity: %d\n", buf, val);
return 0;
}
I stumbled across a weird behaviour in MSVC (2013) recently which I wanted to clarify concerning variable arguments.
It appears having more than one parameter before the '...)' causes unexpected behaviour
int formatString(const char* msg, char* buffer, int bufferLength, ...)
{
int length = 0;
if (msg != nullptr) {
va_list args;
va_start(args, msg);
length = vsnprintf_s(buffer, bufferLength, bufferLength, msg, args);
va_end(args);
}
return length;
}
Calling this function like so
const char* message = "A word: %s and a number %d";
const int bufferLength = 1024;
char buffer[bufferLength];
int formattedMsgLen = formatString(message, buffer, bufferLength, "cheese", 4);
Will immediately cause the program to crash. If I memset the buffer to 0 before
memset(buffer, 0, 1024); // We know sizeof(char) == 1
This is written to the buffer:
"A word: A word: and a number 1024".
Which is completely wrong...
If however, I change the function to take a struct with the first three arguments combined
struct Message
{
const char* msg;
char* buffer;
int bufferLength;
};
int formatString(Message msg, ...)
{
int length = 0;
if (msg.msg != nullptr) {
va_list args;
va_start(args, msg);
length = vsnprintf_s(msg.buffer, msg.bufferLength, msg.bufferLength, msg.msg, args);
va_end(args);
}
return length;
}
When calling the new function like so:
const int bufferLength = 1024;
char buffer[bufferLength];
Message msg;
msg.buffer = buffer;
msg.msg = "A word: %s and a number %d";
msg.bufferLength = bufferLength;
int formattedMsgLen = formatString(msg, "cheese", 4);
This is written to the buffer:
"A word: cheese and a number 4"
Which is correct and this is what I would expect. Am I right in thinking you are only able to use vaargs with a function with only one parameter before? I don't think this is the case as the functions below have more than one first parameter
int fprintf(FILE *, const char *fmt, ...);
int sprintf(char *s, const char *fmt, ...);
Could this potentially be a bug in the compiler? However unlikely....
It probably isn't and I've done something stupid but I am definitely confused by what is happening. If anyone can shed some light on this I would be very grateful.
Thanks!
va_start() must be called with the name of the last parameter before the variable argument list:
int formatString(const char* msg, char* buffer, int bufferLength, ...)
{
// ...
va_list args;
// va_start(args, msg); <-- WRONG!
va_start(args, bufferLength);
// ...
}
I've tried a lot of solutions, but none of them is working.
printf("Test : %d", 123);
std::cout << "Test" << 123 << std::endl;
...
Actually I've setup my project's debugger like this, I'm able to write in the console using OutputDebugStringA("Test"); but this function doesn't accept more than one parameter.
How can I print something like this : ("Test : %d", 123)?
Bogy's answer is on the right track but I don't like the allocation in GetWC which looks like a memory leak, and it uses unsafe functions, try this:
void Debug::Log(const wchar_t *format, ...)
{
wchar_t buffer[BUFFER_LENGTH];
va_list args;
va_start(args, format);
_vsnwprintf_s(buffer, BUFFER_LENGTH, _TRUNCATE, format, args);
va_end(args);
buffer[BUFFER_LENGTH - 1] = '\0'; //prevent buffer overflow
OutputDebugString(buffer);
}
Usage like:
Debug::Log(L"Hello %S\n", "sailor");
I found this code in a C++ training on Pluralsight that I am using for Windows 8 (you just say TRACE("Test : %d", 123); to use it):
#pragma once
#include <assert.h>
#define ASSERT assert
#ifdef _DEBUG
inline auto Trace(wchar_t const * format, ...) -> void
{
va_list args;
va_start(args, format);
wchar_t buffer[256];
ASSERT(-1 != _vsnwprintf_s(buffer, _countof(buffer) - 1, format, args));
va_end(args);
OutputDebugString(buffer);
}
#endif
struct Tracer
{
char const * m_filename;
unsigned m_line;
Tracer(char const * filename, unsigned const line) :
m_filename{ filename },
m_line{ line }
{
}
template <typename... Args>
auto operator()(wchar_t const * format, Args... args) const -> void
{
wchar_t buffer[256];
auto count = swprintf_s(buffer, L"%S(%d): ", m_filename, m_line);
ASSERT(-1 != count);
ASSERT(-1 != _snwprintf_s(buffer + count, _countof(buffer) - count, _countof(buffer) - count - 1, format, args...));
OutputDebugString(buffer);
}
};
#ifdef _DEBUG
#define TRACE Tracer(__FILE__, __LINE__)
#else
#define TRACE __noop
#endif
I've finally found this solution (here and here) :
Debug.cpp:
#pragma once
#include "pch.h"
#define BUFFER_LENGTH 1024
//char* to wchar_t*
const wchar_t *GetWC(const char *c)
{
const size_t cSize = strlen(c) + 1;
wchar_t* wc = new wchar_t[cSize];
mbstowcs(wc, c, cSize);
return wc;
}
void Debug::Log(const char *format, ...)
{
char buffer[BUFFER_LENGTH];
va_list args;
va_start(args, format);
vsnprintf(buffer, BUFFER_LENGTH, format, args);
va_end(args);
buffer[BUFFER_LENGTH - 1] = '\0'; //prevent buffer overflow
OutputDebugString(GetWC(buffer));
}
Debug.h:
class Debug{
public:
static void Log(const char *format, ...);
};
We can use it like printf function:
Debug::Log("Test : %d", 123);