vsnwprintf alternative on linux - c

What is the direct alternative for the vsnwprintf function on linux machines and what headers should be included to use it?
Thanks for any advice

It depends on what vsnwprintf() (sic) does and what is its parameter list.
The C99 Standard describes vswprintf() (in section 7.24.2.7). To use it you need to #include <stdarg.h> and <wchar.h>. The implementation should be in the Standard library.

Linux variant of this function is snprintf and vsnprintf which are kindly provided by stdio.h:
int snprintf(char *str, size_t size, const char *format, ...);
int vsnprintf(char *str, size_t size, const char *format, va_list args);
and Unicode versions provided by wchar.h:
int swprintf(wchar_t *wcs, size_t maxlen, const wchar_t *format, ...);
int vswprintf(wchar_t *wcs, size_t maxlen, const wchar_t *format, va_list args);
http://linux.die.net/man/3/snprintf
http://linux.die.net/man/3/swprintf

There’s no alternative for that.
vswprintf suggested in other answers doesn’t tell required buffer length. When you’ll pass nullptr and 0 to the first two arguments, it will returns -1, not the required buffer length. This is both how it's documented, and how it works in practice in clang 4.
There’s a workaround in that answer
https://stackoverflow.com/a/16352146/126995
Scroll to the end of that for vscwprintf source code. The workaround works for small strings, but relatively slow for larger strings, and can even exhaust stack space for a very large string.

Seems that u_vsnprintf() or u_vsnprintf_u() from libicu is what you need

The truncating version of vswprintf() is unsafe.
You really want the C11 vswprintf_s(), which ensures a null delimited wide string, and errors when the destination buffer is too small.
As you know, the wide variants have no API to calculate the size with a NULL buffer. You need to extend the buffer on errors, if the buffer is too small.
Anyway, safeclib-3.0 will provide all of them.
safe and unsafe with --enable-unsafe, wide or non-wide, truncating ('n') or not-truncating.
https://github.com/rurban/safeclib/blob/wchar/src/wchar/vsnwprintf_s.c
vsnwprintf is in C99, MSVC, and a few others. Not in musl.
-stc=c99 should be enough for glibc.

Here an example of workaround:
int vsnwprintf(wchar_t* buffer, size_t size, const wchar_t* format, va_list& params)
{
if(buffer || size)
return vswprintf(buffer, size, format, params);
int result = -1;
for(size = 100; result < 0; size += 100)
{
unique_ptr<wchar_t[]> guard(buffer = new wchar_t[size]);
va_list copy;
va_copy(copy, params);
result = vswprintf(buffer, size, format, copy);
va_end(copy);
}
return result;
};
Probably, it's needed to limit a number of iterations in some way.

For C++, you can use fmt::sprintf of libfmt from <fmt/printf.h>

Related

Is there a C function like sprintf in the Linux kernel?

Is there function like sprintf() in Linux Kernel (like printf()->printk())?
yes.
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/lib/vsprintf.c#n1828
int snprintf(char *buf, size_t size, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i = vsnprintf(buf, size, fmt, args);
va_end(args);
return i;
}
EXPORT_SYMBOL(snprintf);
sprintf() by itself is prone to buffer overflows. CERT buffer overflows, Apple, etc
Yes, just include linux/kernel.h
yes there is check out here for example
you can use grep to see if it is in the kernel's source code
Running crash on a live 2.6 kernel confirms sprintf() is defined, and where it is defined.
crash> sym sprintf
ffffffff81267ba0 (T) sprintf ../debug/kernel-2.6.39/linux-2.6.39-400.210.2.el6uek/lib/vsprintf.c: 1442
sprintf() is unsafe because of buffer overflow.
If you need to pass data from user space to kernel space, use instead copy_from_user(); it acts like copy_to_user() but in reverse direction.

Adding formatting support to a custom string implementation - C

I have a C application (not using C99 features) that does some heavy string processing. Since the string lengths are not known, statically allocated buffers is not an option for me. I have created a simple string implementation which will abstract the null termination and dynamic expansion of buffers.
Here is how it looks like,
struct strbuf {
char *buffer; /* null terminated buffer */
size_t length; /* length of the string excluding null terminator */
size_t allocated; /* total memory allocated */
};
add function which adds the supplied string into the buffer.
int strbuf_add(struct strbuf *string, const char *c)
{
if(string == NULL) return 0;
while(*c != '\0') {
if(!add_char(string, *c++))
return 0;
}
return 1;
}
static int add_char(struct strbuf *string, char c)
{
size_t space_available;
assert(string != NULL);
space_available = string->allocated - string->length;
if(space_available <= 1) {
if(!grow_buffer(string)) {
return 0;
}
}
string->buffer[string->length++] = c;
string->buffer[string->length] = '\0';
return 1;
}
Now, I need to add a new method something like, addformatted which will take a format like sprintf. I am wondering what would be the best way to do this? Following are my thoughts.
Use vsnprintf. But I am not sure that this is portable and has got the same behaviour on all platforms.
Write a format parser myself. But this seems to be more work.
Any help in implementing this would be great. I am only interested in portable solutions.
Dev Env : Linux with GCC
Expected to compile on MSVC
snprintf is the way to go and has well-defined behavior, but there are some broken implementations where it returns the wrong values when the buffer is too small. Personally I would just ignore broken implementations unless you really need to use one, or provide a custom implementation of the whole printf family to replace the system version on such broken systems. Otherwise you need to research the broken behavior these systems exhibit and find out how to write workarounds. It might require progressively enlarging the buffer over and over until your call succeeds.
When you use sprintf, you must have some idea of what the resulting string length will be, or else you use snprintf and shield yourself from buffer overflows.
If you want this kind of interface, you can create a function that wraps snprintf and takes as argument a buffer length, and expand your string the required amount before calling snprintf.

Is there a function akin to fprintf but only returns the result of formated string in C?

fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
I don't want to output anything via fprintf,but only the result of "Error in pcap_findalldevs: %s\n", errbuf,what's the function for that?
snprintf allows you to format to a char buffer and performs bounds checking to ensure the buffer is not overrun.
The commonly used sprintf does not perform bounds checking, and as such is inherently unsafe.
int sprintf(char * ptr, const char * format, ...)
Writes the output and a terminating null to a buffer at ptr, returns the number of characters written excluding the null. Dangerous if you don't know how big your output should be, it will blindly write past the end of the buffer.
int snprintf(char * ptr, size_t n, const char * format, ...)
Same as sprintf, but will write a maximum of n characters, including the trailing null. Returns the number of characters that would be written if n was large enough, so that you can reallocate your buffer if necessary.
int asprintf(char ** ptr, const char * format, ...)
Same as sprintf except a double pointer is passed in, the buffer will be resized if necessary to fit the output. This is a GNU extension, also available in BSD, it can be emulated like (Ignoring error checking)
int asprintf(char ** ptr, const char * format, ...){
va_list vlist;
va_start(vlist,format);
int n = vsnprintf(NULL,0,format,vlist);
*ptr = realloc(*ptr,n+1);
n = vsnprintf(*ptr,n+1,format,vlist);
va_end(vlist);
return n;
}
That is sprintf() which also has some useful variations, like vsprintf() which takes a pointer to an argument list. There are also buffer protection versions in some implementations.
sprintf copies the result to a char * instead of writing it to stdout or a file.
Syntax differences
printf(const char format, ...)
fprintf(FILE * file, const char format, ...)
sprintf(char * string, const char format, ...)
sprintf is the original call, but should be considered deprecated in favor of snprintf which allows you to pass a size. Another alternative is asprintf, which will allocate a string large enough to hold the result.

Can you write to a byte array using a FILE*

C# has a neat feature of being able to write to a memory stream using the MemoryStream object.
I'm looking for similar functionality from C using a FILE* pointer.
I want to be able to sprintf() but with the added functionality of having C remember "where I was" in the buffer I'm writing to.
If you are using the GNU C Library, you can use fmemopen(). There may be other non-portable extensions for other environments, but there's no portable way using FILE*s.
You could also, however, wrap snprintf, if you don't insist on actually using FILE*s. For example, glib (note: not the same as the GNU C Library, and portable) has a g_string_append_printf that does what you want.
There's also an ugly hack which works with plain ISO-C: You can use fopen() to open a null file (/dev/null on *nix, NUL on Windows) and set the array as the file's buffer via
setvbuf(file, buffer, _IOFBF, buffer_size)
This should work fine as long as fflush() isn't called anywhere in the code. Also, the programmer has to explicitly take care of the string delimiter.
I don't really see a need to do this, though: As snprintf() returns the number of characters written, it's trivial to keep track of a buffer's position.
One can even write a function to automagically resize the buffer on overflow: bufprintf.c
The function's prototype is
int bufprintf(char **buffer, size_t *size, size_t *offset,
const char *format, ...);
An example program could look like this:
#include <stdio.h>
extern int bufprintf(char **buffer, size_t *size, size_t *offset,
const char *format, ...);
int main(void)
{
size_t size = 0; // must be set!
size_t offset;
char * buffer;
for(int i = 0; i < 100; ++i)
bufprintf(&buffer, &size, &offset, "we rock %i\n", i);
puts(buffer);
printf("size:\t%u\noffset:\t%u\n", (unsigned)size, (unsigned)offset);
}
sprintf returns the number of characters that were printed into the string. You can use that value to increment the pointer of your buffer.
buffer += sprintf(buffer, "%d", i);
Make sure that you keep around a copy of the original pointer, as that is what you will be using when passing the buffer somewhere else.
Why not use mmap? You can map a file to memory and use a FILE* pointer.
Update: It does not work. Sorry.
MemoryStream is not a feature of C#, the language. It's simply a class in the BCL. You could write it yourself in C#.
And so it is in C - you'd write some functions that work similarly in use to fopen, fprintf, fwrite, fclose, etc., but give them names like mopen, mwrite, etc. (presumably) and write them so they operate on a memory buffer.
How about just manually managing your pointers. I don't have a compiler in front me but hopefully the code below gets the idea across:
char huge_buffer[REALLY_BIG_SIZE];
char *write_pos = huge_buffer;
//...
void fprintf_to_mem(char **mem_ptr, const char *fmt, ...)
{
va_list args;
int num_written;
va_start(args, mem_ptr);
num_written = vsprintf(*write_pos, fmt, args);
*write_pos += num_written;
va_end(args);
}
//...
fprintf_to_mem(&write_pos, "Testing %d %d %d", 1, 2, 3);
fprintf_to_mem(&write_pos, "Hello world!\r\n");
I would expect that to output "Testing 1 2 3Hello world!\r\n" to huge_buffer.

Creating C formatted strings (not printing them)

I have a function that accepts a string, that is:
void log_out(char *);
In calling it, I need to create a formatted string on the fly like:
int i = 1;
log_out("some text %d", i);
How do I do this in ANSI C?
Only, since sprintf() returns a int, this means that I have to write at least 3 commands, like:
char *s;
sprintf(s, "%d\t%d", ix, iy);
log_out(s);
Any way to shorten this?
Use sprintf. (This is NOT safe, but OP asked for an ANSI C answer. See the comments for a safe version.)
int sprintf ( char * str, const char * format, ... );
Write formatted data to string Composes a string with the same text
that would be printed if format was used on printf, but instead of
being printed, the content is stored as a C string in the buffer
pointed by str.
The size of the buffer should be large enough to contain the entire
resulting string (see snprintf for a safer version).
A terminating null character is automatically appended after the
content.
After the format parameter, the function expects at least as many
additional arguments as needed for format.
Parameters:
str
Pointer to a buffer where the resulting C-string is stored. The buffer
should be large enough to contain the resulting string.
format
C string that contains a format string that follows the same
specifications as format in printf (see printf for details).
... (additional arguments)
Depending on the format string, the function may expect a sequence of
additional arguments, each containing a value to be used to replace a
format specifier in the format string (or a pointer to a storage
location, for n). There should be at least as many of these arguments
as the number of values specified in the format specifiers. Additional
arguments are ignored by the function.
Example:
// Allocates storage
char *hello_world = (char*)malloc(13 * sizeof(char));
// Prints "Hello world!" on hello_world
sprintf(hello_world, "%s %s!", "Hello", "world");
If you have a POSIX-2008 compliant system (any modern Linux), you can use the safe and convenient asprintf() function: It will malloc() enough memory for you, you don't need to worry about the maximum string size. Use it like this:
char* string;
if(0 > asprintf(&string, "Formatting a number: %d\n", 42)) return error;
log_out(string);
free(string);
This is the minimum effort you can get to construct the string in a secure fashion. The sprintf() code you gave in the question is deeply flawed:
There is no allocated memory behind the pointer. You are writing the string to a random location in memory!
Even if you had written
char s[42];
you would be in deep trouble, because you can't know what number to put into the brackets.
Even if you had used the "safe" variant snprintf(), you would still run the danger that your strings gets truncated. When writing to a log file, that is a relatively minor concern, but it has the potential to cut off precisely the information that would have been useful. Also, it'll cut off the trailing endline character, gluing the next log line to the end of your unsuccessfully written line.
If you try to use a combination of malloc() and snprintf() to produce correct behavior in all cases, you end up with roughly twice as much code than I have given for asprintf(), and basically reprogram the functionality of asprintf().
If you are looking at providing a wrapper of log_out() that can take a printf() style parameter list itself, you can use the variant vasprintf() which takes a va_list as an argument. Here is a perfectly safe implementation of such a wrapper:
//Tell gcc that we are defining a printf-style function so that it can do type checking.
//Obviously, this should go into a header.
void log_out_wrapper(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
void log_out_wrapper(const char *format, ...) {
char* string;
va_list args;
va_start(args, format);
if(0 > vasprintf(&string, format, args)) string = NULL; //this is for logging, so failed allocation is not fatal
va_end(args);
if(string) {
log_out(string);
free(string);
} else {
log_out("Error while logging a message: Memory allocation failed.\n");
}
}
It sounds to me like you want to be able to easily pass a string created using printf-style formatting to the function you already have that takes a simple string. You can create a wrapper function using stdarg.h facilities and vsnprintf() (which may not be readily available, depending on your compiler/platform):
#include <stdarg.h>
#include <stdio.h>
// a function that accepts a string:
void foo( char* s);
// You'd like to call a function that takes a format string
// and then calls foo():
void foofmt( char* fmt, ...)
{
char buf[100]; // this should really be sized appropriately
// possibly in response to a call to vsnprintf()
va_list vl;
va_start(vl, fmt);
vsnprintf( buf, sizeof( buf), fmt, vl);
va_end( vl);
foo( buf);
}
int main()
{
int val = 42;
foofmt( "Some value: %d\n", val);
return 0;
}
For platforms that don't provide a good implementation (or any implementation) of the snprintf() family of routines, I've successfully used a nearly public domain snprintf() from Holger Weiss.
Don't use sprintf.
It will overflow your String-Buffer and crash your Program.
Always use snprintf
If you have the code to log_out(), rewrite it. Most likely, you can do:
static FILE *logfp = ...;
void log_out(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(logfp, fmt, args);
va_end(args);
}
If there is extra logging information needed, that can be printed before or after the message shown. This saves memory allocation and dubious buffer sizes and so on and so forth. You probably need to initialize logfp to zero (null pointer) and check whether it is null and open the log file as appropriate - but the code in the existing log_out() should be dealing with that anyway.
The advantage to this solution is that you can simply call it as if it was a variant of printf(); indeed, it is a minor variant on printf().
If you don't have the code to log_out(), consider whether you can replace it with a variant such as the one outlined above. Whether you can use the same name will depend on your application framework and the ultimate source of the current log_out() function. If it is in the same object file as another indispensable function, you would have to use a new name. If you cannot work out how to replicate it exactly, you will have to use some variant like those given in other answers that allocates an appropriate amount of memory.
void log_out_wrapper(const char *fmt, ...)
{
va_list args;
size_t len;
char *space;
va_start(args, fmt);
len = vsnprintf(0, 0, fmt, args);
va_end(args);
if ((space = malloc(len + 1)) != 0)
{
va_start(args, fmt);
vsnprintf(space, len+1, fmt, args);
va_end(args);
log_out(space);
free(space);
}
/* else - what to do if memory allocation fails? */
}
Obviously, you now call the log_out_wrapper() instead of log_out() - but the memory allocation and so on is done once. I reserve the right to be over-allocating space by one unnecessary byte - I've not double-checked whether the length returned by vsnprintf() includes the terminating null or not.
Verified and Summary:
sprintf vs asprintf
asprintf = malloc + sprintf
sample code
sprintf
int largeEnoughBufferLen = 20;
char *someStr = (char*)malloc(largeEnoughBufferLen * sizeof(char));
sprintf(someStr, "formatted string: %s %s!", "Hello", "world");
// do what you want for formatted string: someStr
free(someStr);
asprintf
char *someStr;
int formattedStrResult = asprintf(&someStr, "formatted string: %s %s!", "Hello", "world");
if(formattedStrResult > 0){
// do what you want for formatted string: someStr
free(someStr);
} else {
// some error
}
I haven't done this, so I'm just going to point at the right answer.
C has provisions for functions that take unspecified numbers of operands, using the <stdarg.h> header. You can define your function as void log_out(const char *fmt, ...);, and get the va_list inside the function. Then you can allocate memory and call vsprintf() with the allocated memory, format, and va_list.
Alternately, you could use this to write a function analogous to sprintf() that would allocate memory and return the formatted string, generating it more or less as above. It would be a memory leak, but if you're just logging out it may not matter.
http://www.gnu.org/software/hello/manual/libc/Variable-Arguments-Output.html gives the following example to print to stderr. You can modify it to use your log function instead:
#include <stdio.h>
#include <stdarg.h>
void
eprintf (const char *template, ...)
{
va_list ap;
extern char *program_invocation_short_name;
fprintf (stderr, "%s: ", program_invocation_short_name);
va_start (ap, template);
vfprintf (stderr, template, ap);
va_end (ap);
}
Instead of vfprintf you will need to use vsprintf where you need to provide an adequate buffer to print into.

Resources