Gerald Pfeifer gerald@pfeifer.com writes:
Add proper casts to avoid signed vs. unsigned mismatches in strmake().
if (n > -1 && n < size) return p;
- size = min( size*2, n+1 );
if (n > -1 && (size_t)n < size) return p;
- size = min( size*2, (size_t)n+1 );
Once at it, could you please explain to me what the hell is going on here (min)? I came across this function recently, and do not agree with its logic. I would write it like
char *strmake(const char *fmt, ...) { int n; size_t size = 100; char *p = xmalloc (size+1); va_list ap;
va_start (ap, fmt); n = vsnprintf (p, size, fmt, ap); while (n < 0) { size *= 2; p = xrealloc (p, size+1); n = vsnprintf (p, size, fmt, ap); } if ((size_t)n == size) p[size]=0; va_end (ap); return p; }
By the way, either Wine's snprintf implementation is wrong or I do not know how to use it correctly. I am submitting a conformance test...
On October 30, 2003 07:28 pm, Ferenc Wagner wrote:
if (n > -1 && n < size) return p;
size = min( size*2, n+1 );
if (n > -1 && (size_t)n < size) return p;
size = min( size*2, (size_t)n+1 );
Once at it, could you please explain to me what the hell is going on here (min)?
Well, the way I see it, it's just trying to minimize memory usage in a portable manner. Normally, vsnprintf() should return the necessary size of the buffer (in n), if the current size is too small. If however vsnprintf() fails to return that, we should just double the size of the buffer until we have something large enough.
Now, the way the code it's written right now will not work if vsnprintf() returns -1 for failure. Question is, do we really need to worry about vsnprintf() not returning the correct size of the required buffer?
BTW, IIRC the code has been taken from one of glibc's man pages...
"Dimitrie O. Paun" dpaun@rogers.com writes:
On October 30, 2003 07:28 pm, Ferenc Wagner wrote:
if (n > -1 && n < size) return p;
size = min( size*2, n+1 );
if (n > -1 && (size_t)n < size) return p;
size = min( size*2, (size_t)n+1 );
Once at it, could you please explain to me what the hell is going on here (min)?
Well, the way I see it, it's just trying to minimize memory usage in a portable manner. Normally, vsnprintf() should return the necessary size of the buffer (in n), if the current size is too small.
In libc-2.1 and later, yes it should. According to MSDN (and pre-2.1 libc docs), it should not.
Now, the way the code it's written right now will not work if vsnprintf() returns -1 for failure.
It does on XP. The new conformance tests tells it all... If written correctly. See below.
Question is, do we really need to worry about vsnprintf() not returning the correct size of the required buffer?
Seems like this is the case under Windows. Not under any reasonable modern GNU/Linuxes. However, writing portable code is easy: if the returned value exceeds the buffer length, allocate that much memory and repeat once. No need to loop in this case.
By the way, I really managed to screw myself (and my gcc) up by mixing libc calls into winetests. After yesterday's cvs update, it started to behave really strange. It was sort of working before (creating temporary files under /tmp), but after the update it is creating a directory called "C:\TEMP\wctX" under programs/winetests... It took me some good time to realise this, and I could not stop laughing when I finally did. It is obviously some funny mixture of libc and msvcrt functions, probably due to ./configure recreating the Makefile... So I could use some clarification on this issue. What I think is:
Normally I use the Unix libc functions. If I #include "config.h" #include "wine/port.h" and -lwine_port, I use the Windows runtime (msvcrt). By prepending and underscore, I always get the msvcrt functions.
But what is the truth? The scanf.c test clearly contradicts the above theory. I may be better off using the _names to avoid this confusion...
Feri.
On November 3, 2003 06:09 am, Ferenc Wagner wrote:
In libc-2.1 and later, yes it should. According to MSDN (and pre-2.1 libc docs), it should not.
OK, so we need to care about n not being the size of the required buffer.
Seems like this is the case under Windows. Not under any reasonable modern GNU/Linuxes. However, writing portable code is easy: if the returned value exceeds the buffer length, allocate that much memory and repeat once. No need to loop in this case.
No harm in looping either -- if the correct value is returned, we will just exit right away. If we know for sure that size_t is unsigned (is it always?), than the min() will work just fine. Otherwise, we can rewrite that line as:
size = n < 0 ? size*2 : n+1;
We should probably should anyway, as it makes it a lot more clearer WTF is going on.
By the way, I really managed to screw myself (and my gcc) up by mixing libc calls into winetests.
"Doctor, it hurts when I do that..." :))) I'd say, don't do it. Just use libc calls, don't link against msvcrt. Any reason we need to link against msvcrt at all?
"Dimitrie O. Paun" dpaun@rogers.com writes:
If we know for sure that size_t is unsigned (is it always?), than the min() will work just fine.
Oh yes, now I get it! It works because -1 is the largest unsigned integer! Amazing... not too transparent, though.
Otherwise, we can rewrite that line as:
size = n < 0 ? size*2 : n+1;
We should probably should anyway, as it makes it a lot more clearer WTF is going on.
Even I could understand this code... And this also handles the case when the string exactly fits the buffer but the closing zero does not. Great, the original code is actally correct, I am simply too dumb to understand it. :)
Just use libc calls, don't link against msvcrt. Any reason we need to link against msvcrt at all?
This will be a windows application after all... Running on native Windows. We can not use Unixism, or can we? By the way, why does the scanf test work? Because msvcrt is linked before libc? What decides which sscanf will be called?
Feri.
On November 3, 2003 08:01 am, Ferenc Wagner wrote:
This will be a windows application after all... Running on native Windows. We can not use Unixism, or can we? By the
Yes, but it can be a Winelib app as well. Theoretically we should use only stuff that is portable between libc and msvcrt.
way, why does the scanf test work? Because msvcrt is linked before libc? What decides which sscanf will be called?
Yes, I think it is linked before libc. Try not linking against msvcrt, see what happens.