473,748 Members | 7,571 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

looking for statefull snprintf

Hello

Here is my situation: I have a char buf[1024]; that is used as a buffer

for a log output. Normally, I do:

rc = snprintf( buf, sizeof(buf), some_format, some_args );

This makes the formatting my output and then I flush the buffer.
In 90% of cases this works well, exept the cases when the format or the

arguments require more then 1024 bytes of formatted input.
There is no easy way to re-run snprintf() form 'last' position.

Suppose that using of asprintf(), another buffer and other kinds of
malloc() is not an option. Suppose the buffer must be preprocessed
before it hits the actual io.

Is there any open/closed libraries that solve the problem? Are there
any discussions held on the subject? Please provide the references.

Thanks
--
Dima

Aug 17 '06
20 1909
dimka wrote:
Here is my situation: I have a char buf[1024]; that is used as a buffer
for a log output.
You should immediately cringe whenever you find yourself in situations
where you are declaring large arrays like that, basically in hopes that
1024 is close enough to infinity.
[...] Normally, I do:

rc = snprintf( buf, sizeof(buf), some_format, some_args );

This makes the formatting my output and then I flush the buffer.
In 90% of cases this works well, exept the cases when the format or the
arguments require more then 1024 bytes of formatted input.
There is no easy way to re-run snprintf() form 'last' position.
Right, in fact you can't. The arguments are always considered formed
once at compile time. You cannot even process the same va_list more
than once (the standards committee added va_copy to C99, but C99 has
not been widely adopted).
Suppose that using of asprintf(), another buffer and other kinds of
malloc() is not an option. Suppose the buffer must be preprocessed
before it hits the actual io.

Is there any open/closed libraries that solve the problem? Are there
any discussions held on the subject? Please provide the references.
The regulars in this group *cannot* help you. They will cite the
standard, and cannot read well enough to see that you say specifically
that you cannot call malloc() or asprintf().

Ok, the only straight forward "in standard" solution that is possible
for you is to use vfprintf to write the output to a file, then read
back that file in chunks that you can then send to your real output.
Of course this involves the file system and is very likely to be highly
distasteful (what are you supposed to do when the disk is full?).

Another approach, of course, is to go find some open source snprintf's
out there and hack on them to make them do what you want. There are
numerous such snprintf packages out there. However, its also possible
to write your own. Either way, what you're going to want to do is to
change interface to something like:

long vpprintf (long (*output) (const char * fragment, int sz,
void * ctx),
void * ctx, const char * fmt, va_list arg);

The idea is that you would incrementally generate the formatted output
into fragments that you would then emit to the output() function
pointer in pieces (with the length passed in; this is required so that
you can output %c, with a value of '\0'). As a bonus, you would make
it so that if output() returned a negative number vpprintf would stop,
and re-return this value (to do some sort of error propogation.)
Otherwise you would return the total positive number of characters
"written" to the output callback function. Such a solution would
always use a finite amount of memory but be able to process an
arbitrarily long amount of formatted output.

Keep in mind that its not impossible to write this code from scratch
yourself. Primarily you have to break down the formatting and
arguments (via va_arg) yourself, but for the actual conversion you can
generally fall back on just plain old sprintf(). Obviously, you would
detect formatting widths beyond a certain size, and perform some
specially slicing and dicing and iterate it through a single reasonably
sized auto buffer. So there is not need to solve the difficult task of
converting floating point a to string or similar kinds of things.

If you write this code, you will basically be able to solve any problem
you ever have with C-style formatted output just using this interface.
What this says about the C standard committee (i.e., the fact that this
function or equivalent (i.e., allow for FILE *'s to wrap function
callbacks) doesn't already exist) I will leave for you to decide.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Aug 17 '06 #11
"dimka" <di************ @gmail.comwrite s:
Well, let me explain the problem again.
Lets assume that the buffer is empty, thus no need to flush it.
then

rc = snprintf( buffer, sizeof(buffer)-1, "%s", str );

Works pretty well. No buffer overrun, in the new standard
rc == strlen(str), in old standard rc == -1, thus I have a way
to check that there was the potential overrun.

The problem arises when strlen(str) sizeof(buffer).
In this situation the buffer will contain trunkated version
of str, I have the information that the string was
trunkated, but no way to say "hey, I have flushed the
buffer, please continue from the place where you
stopped". There must to be an alternative implementation
of snprintf() to do exactly what I want.
You still haven't explained why you can't just enlarge the buffer
and rerun snprintf in the enlarged buffer.
--
"I don't have C&V for that handy, but I've got Dan Pop."
--E. Gibbons
Aug 18 '06 #12
dimka wrote:
>
This is funny :) Everyone can cite the standard. But this is EXACTLY
the code that does NOT work.
Don't top-post. Read the code again. Note that it first tests for
overflow, and if such would occur flushes the buffer and marks it
empty. The only assumption is that a single output string fits in
the buffer.

This design is intended to reuse a buffer, but mitigate the system
interruption to perform actual output.

--
"The power of the Executive to cast a man into prison without
formulating any charge known to the law, and particularly to
deny him the judgement of his peers, is in the highest degree
odious and is the foundation of all totalitarian government
whether Nazi or Communist." -- W. Churchill, Nov 21, 1943
Aug 18 '06 #13
we******@gmail. com wrote:
dimka wrote:
>Here is my situation: I have a char buf[1024]; that is used as a
buffer for a log output.
.... snip ...
>
Right, in fact you can't. The arguments are always considered formed
once at compile time. You cannot even process the same va_list more
than once (the standards committee added va_copy to C99, but C99 has
not been widely adopted).
>Suppose that using of asprintf(), another buffer and other kinds of
malloc() is not an option. Suppose the buffer must be preprocessed
before it hits the actual io.

Is there any open/closed libraries that solve the problem? Are there
any discussions held on the subject? Please provide the references.

The regulars in this group *cannot* help you. They will cite the
standard, and cannot read well enough to see that you say specifically
that you cannot call malloc() or asprintf().

Ok, the only straight forward "in standard" solution that is possible
for you is to use vfprintf to write the output to a file, then read
back that file in chunks that you can then send to your real output.
Of course this involves the file system and is very likely to be highly
distasteful (what are you supposed to do when the disk is full?).
If you take the trouble to read the solution I posted, you will
find that there are no calls to malloc etc. involved, and that the
buffer is never overwritten. It only involves a few lines of code,
and no tortuous rebuilding of the wheel as you advise. The key is
that snprintf(NULL, 0, ....) returns the output length without any
actual output. Ben has pointed out that some libraries do not
adhere to the standard, but that is a QOI issue.

--
"The power of the Executive to cast a man into prison without
formulating any charge known to the law, and particularly to
deny him the judgement of his peers, is in the highest degree
odious and is the foundation of all totalitarian government
whether Nazi or Communist." -- W. Churchill, Nov 21, 1943
Aug 18 '06 #14
CBFalconer wrote:
we******@gmail. com wrote:
dimka wrote:
Here is my situation: I have a char buf[1024]; that is used as a
buffer for a log output.
... snip ...

Right, in fact you can't. The arguments are always considered formed
once at compile time. You cannot even process the same va_list more
than once (the standards committee added va_copy to C99, but C99 has
not been widely adopted).
Suppose that using of asprintf(), another buffer and other kinds of
malloc() is not an option. Suppose the buffer must be preprocessed
before it hits the actual io.

Is there any open/closed libraries that solve the problem? Are there
any discussions held on the subject? Please provide the references.
The regulars in this group *cannot* help you. They will cite the
standard, and cannot read well enough to see that you say specifically
that you cannot call malloc() or asprintf().

Ok, the only straight forward "in standard" solution that is possible
for you is to use vfprintf to write the output to a file, then read
back that file in chunks that you can then send to your real output.
Of course this involves the file system and is very likely to be highly
distasteful (what are you supposed to do when the disk is full?).

If you take the trouble to read the solution I posted, you will
find that there are no calls to malloc etc. involved,
I *DID* read your post. It just plain doesn't work, as the OP was
immediately able to point out. But that's just par for the course with
you, so I didn't bother pointing it out directly.
[...] and that the buffer is never overwritten.
I don't even know what you mean here -- even *your* solution reuses the
buffer, but that is only step 1 in trying to solve this.
[...] It only involves a few lines of code,
and no tortuous rebuilding of the wheel as you advise.
And that's fine if the OP doesn't care to have a working solution. My
solution is only meant for the very narrow goal of correctly answering
the OP's question as asked. As to the much broader scope of irrelevant
answers that obviously don't work, I'll leave that to you.
[...] The key is
that snprintf(NULL, 0, ....) returns the output length without any
actual output. Ben has pointed out that some libraries do not
adhere to the standard, but that is a QOI issue.
*MANY* libraries do not adhere to the standard. Go look at the source
for asprintf, or in fact my bformat(a) functions in Bstrlib. We go to
very extreme lengths to tease out the results we want because of the
really poor state of standards compliance on that function.

QOI issue or not, that OP was not asking for a platform specific
solution (isn't that supposed to be OT in this newsgroup?) and was not
asking for a non-functional solution (which you and Ben seemed happy to
provide) either.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Aug 18 '06 #15
we******@gmail. com wrote:
CBFalconer wrote:
.... snip ...
>>
If you take the trouble to read the solution I posted, you will
find that there are no calls to malloc etc. involved,

I *DID* read your post. It just plain doesn't work, as the OP was
immediately able to point out. But that's just par for the course
with you, so I didn't bother pointing it out directly.
No you didn't read the code, or you are incapable of reading
standard C. From your cavalier attitude to standards I suspect the
latter. I even posted a portion of the standard to justify the
technique.
>
>[...] and that the buffer is never overwritten.

I don't even know what you mean here -- even *your* solution reuses the
buffer, but that is only step 1 in trying to solve this.
Here I meant that there never is any overflow. Poorly worded by
me. I guess you require very short monosyllabic phrases. Buffers
are normally intended to be filled and emptied. Believe it or not,
memory is a limited resource.

I apologize for using three and four syllable words, but I find it
hard to express myself without them. You can find most of them in
any dictionary.

--
"The power of the Executive to cast a man into prison without
formulating any charge known to the law, and particularly to
deny him the judgement of his peers, is in the highest degree
odious and is the foundation of all totalitarian government
whether Nazi or Communist." -- W. Churchill, Nov 21, 1943

Aug 18 '06 #16
CBFalconer wrote:
we******@gmail. com wrote:
CBFalconer wrote:
... snip ...
If you take the trouble to read the solution I posted, you will
find that there are no calls to malloc etc. involved,
I *DID* read your post. It just plain doesn't work, as the OP was
immediately able to point out. But that's just par for the course
with you, so I didn't bother pointing it out directly.

No you didn't read the code, or you are incapable of reading
standard C. From your cavalier attitude to standards I suspect the
latter. I even posted a portion of the standard to justify the
technique.
*Sigh*. Ok, from the top:

1. templgh = snprintf(NULL, 0, format, whatever);
2. if (templgh + bufindex >= sizeof(buffer) {
3. flushbuf(buffer ); bufindex = 0;
4. }
5. bufindex += snprintf(buffer[bufindex],
sizeof(buffer) - 1 - bufindex,
format, whatever);

Line 1 has a well known problem; what snprintf outputs on different
systems is just inconsistent, so your test on line 2 just does not
correctly identify the incremental overflow case. You can claim this
is just a violation of the standard, so we will ignore your contempt
for real world systems for the moment.

The first argument of Line 5 *might* make sense if you've declared
buffer to be char buffer[<something>][1024] or something like that, but
then we are screwed back on Line 2 with the sizeof(buffer). Ok, so
just looking at the "units" of each parameter, it seems that you
probably meant &buffer[bufindex] -- I don't know how to proceed in
analyzing your code if I can't make this assumption.

Ok, as the OP points out, "whatever" can be a mass of stuff including a
single 8.5 megabyte string. Now if sizeof(buffer) < the length of the
contents of a formatted "whatever", then what the hell would is line 5
going to do? It will just truncate whatever it is you are trying to
sprintf down to sizeof(buffer)-1 characters. So that's just a wrong
result.

Furthermore format and "whatever" are a complex sequence of arguments
-- restarting them, and this sprintf somehow, just isn't going to cut
it; it can't be done. This is the crux of his problem, and this is
what he is asking. He made the point clearer in a follow-up post (I
got it the first time.) Your ignoring this problem is an interesting
way of trying to answer it, but that doesn't help the OP.
[...] and that the buffer is never overwritten.
I don't even know what you mean here -- even *your* solution reuses the
buffer, but that is only step 1 in trying to solve this.

Here I meant that there never is any overflow.
I see. Well as I point out above, that isn't the problem with your
solution anyways.
[...] Poorly worded by
me. I guess you require very short monosyllabic phrases.
Its not poorly worded -- its wrongly worded. I only require correct
sentences using correct words. I'm fine with you simply correcting
yourself after the fact here (I'm hardly immune to typos myself) but of
course, you had to push it.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Aug 18 '06 #17
There are few reasons:

The application must use minimum heap memory (application environment
is close
to embeded applications, sory but I cant disclose the exact details).
The malloc() is very
expensive. Also, it is very important to keep low rate of the memory
leaks, while allocating the buffer dynamically will require later
clean-up in all possible exception
handling situations. This will increase chanse of the memory leaks.
You still haven't explained why you can't just enlarge the buffer
and rerun snprintf in the enlarged buffer.
Aug 18 '06 #18
You are right. The original question was "does anybody know about open
source vpprintf() implementation? ". The problem is obvious and exists
since sprintf() was invented.
Thus I hope somebody already solved it.

Anyway, thanks for your answers guys!
Another approach, of course, is to go find some open source snprintf's
out there and hack on them to make them do what you want. There are
numerous such snprintf packages out there. However, its also possible
to write your own. Either way, what you're going to want to do is to
change interface to something like:

long vpprintf (long (*output) (const char * fragment, int sz,
void * ctx),
void * ctx, const char * fmt, va_list arg);

Aug 18 '06 #19
[someone -- I cannot quite untangle the attributions at this point --
wrote]
>>>bufindex += snprintf(buffer[bufindex],
sizeof(buffer) - 1 - bufindex,
format, whatever);
This code is obviously wrong: the first argument needs to be
&buffer[bufindex] (or equivalent).

In article <11************ **********@i3g2 000cwc.googlegr oups.com>
dimka <di************ @gmail.comwrote :
>Lets assume that the buffer is empty, thus no need to flush it.
then

rc = snprintf( buffer, sizeof(buffer)-1, "%s", str );

Works pretty well. No buffer overrun, in the new standard
rc == strlen(str), in old standard rc == -1, thus I have a way
to check that there was the potential overrun.

The problem arises when strlen(str) sizeof(buffer).
In this situation the buffer will contain trunkated version
of str, I have the information that the string was
trunkated, but no way to say "hey, I have flushed the
buffer, please continue from the place where you
stopped". There must to be an alternative implementation
of snprintf() to do exactly what I want.
In the general case, this is too hard (MUCH too hard). Consider
what has to happen if, for instance, the format argument is not
just "%s", but instead, we have something like:

int aw, ap; /* width and precision for "a" */
double a; /* value of "a" */
int sw; /* width for "s" */
char *s; /* etc */
int k;
int x;
...
/* there is no need for -1 on sizeof buf; snprintf does that */
x = snprintf(buf, sizeof buf, "%*.*f %*.32s %-12d", aw, ap, a, sw, s, k);

It is possible that, e.g., the printf engine stopped somewhere in
the middle of the "%*.32s", having run out of room for padding or
having run out of the maximum of 32 characters in "s" (or both).
The only reasonable method is to start over, discarding the "unwanted"
characters.

Of course, if your format is always exactly "%s", you do not need
snprintf() at all! The "%s" format just copies a string unchanged,
and the length of the string is simply strlen(str). So given the
simplified version above:

size_t i, part, len;
const char *p;

len = strlen(str);
for (i = len, p = str; i 0; p += part, i -= part) {
/* find out how much of the string fits */
part = sizeof buffer - 1;
if (part len)
part = len;

/* put it in the buffer */
memcpy(buffer, p, part);
buffer[part] = 0;

... do something with buffer ...
/* or, do it directly with p[0]..p[part-1], eliminating the memcpy */
}

You only need snprintf() if the format is complicated, in which
case, you usually need the "restart from beginning" behavior.

If you really need something fancier, you can always write your
own (possibly limited) printf-like function(s) in Standard C. Or,
if you are willing to go beyond Standard C, you can:

- use the funopen() I put in the 4.4BSD stdio, or
- use the GNU equivalent of funopen()

to "open" a stdio stream with a user-supplied "buffer writing"
function, and then supply that stream to fprintf(). Of course
using such extensions, while convenient, gives up all kinds of
portability.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Aug 20 '06 #20

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
2760
by: MaxMax | last post by:
Now... I have a problem... It's an engineering problem. I have a function, we will call it MyBigFunc. It's a function that can be easily built as a static method, because it is the only function that the "user" will use and it is stateless. So I wrote something like: class MyClass { public: static int MyBigFunc() { return 0;}
2
5416
by: ajm | last post by:
Hi, I'm refactoring some HTTP client code I wrote a while back and in the process I'm tightening up some of my string processing code (most of which involves parsing, replacing, concatenating strings etc.). I'm reading that it is better to use str functions like "snprintf" and to avoid using "strcat" altogether since the former more explicit protection against buffer overflow etc. Is this sort of comment good advice ?
2
1642
by: Bruno van Dooren | last post by:
Hi, this might be a strange question, but why is snprintf not guaranteed to nul terminate a string? i thought the whole point of those sn functions was to prevent these errors. sure, they prevent buffer overwrites, but callers can still screw up bad if they don't always make sure for themselves that the 0 is there before they let someone else read the contents.
2
3732
by: A. Farber | last post by:
Hello, I'm programming a web application and for that I'm trying to extend the standard C string functions, so that they can handle the application/x-www-form-urlencoded format (which encodes non-alphanumeric characters as %XY). I've written my own xstrlen(), xstrlcat(), xstrlcpy and xstrdup() (please see the source code on the bottom of this post).
14
13559
by: matevzb | last post by:
The C99 standard describes snprintf() in an awkward way, so it's hard (for me) to assume what the result will be in some situations. 1. The "Description" section states: "... Otherwise, output characters beyond the n-1st are discarded rather than being written to the array, and a null character is written at the end of the characters actually written into the array." 2. The "Returns" section states: "The snprintf function returns the...
0
802
by: ymsfa | last post by:
hello I would like to know how to access a statefull java web service from c#, I created a c# client but it dosen't maintain a statefull session and I found another method created by VS ( getInstAsync() ) however my web service method is getInst() why VS created another method ending with (Async)? so, my question is how to access a statefull java web service from c# application? thanks
11
44847
by: manjuks | last post by:
Hi All, I wants to know what is the difference between sprintf and snprintf? Thanks, Manjunath
0
8830
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9544
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9372
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
9247
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
6796
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4606
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4874
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3313
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2783
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.