1
0
mirror of https://github.com/moparisthebest/wget synced 2024-07-03 16:38:41 -04:00

[svn] Fix varargs usage in logvprintf.

Published in <sxs667knbe1.fsf@florida.arsdigita.de>.
This commit is contained in:
hniksic 2001-12-05 21:53:21 -08:00
parent fcf68c0e9a
commit f8e6feb6bc
2 changed files with 122 additions and 79 deletions

View File

@ -1,3 +1,10 @@
2001-12-06 Hrvoje Niksic <hniksic@arsdigita.com>
* log.c (logvprintf): Restructure to allow being called multiple
times.
(logprintf): Call logvprintf in a loop.
(debug_logprintf): Ditto.
2001-12-06 Hrvoje Niksic <hniksic@arsdigita.com>
* gen_sslfunc.c (ssl_init_prng): Allow the user to disable EGD by

194
src/log.c
View File

@ -281,84 +281,92 @@ logputs (enum log_options o, const char *s)
needs_flushing = 1;
}
struct logvprintf_state {
char *bigmsg;
int expected_size;
int allocated;
};
/* Print a message to the log. A copy of message will be saved to
saved_log, for later reusal by log_dump(). */
saved_log, for later reusal by log_dump().
static void
logvprintf (enum log_options o, const char *fmt, va_list args)
It is not possible to code this function in a "natural" way, using
a loop, because of the braindeadness of the varargs API.
Specifically, each call to vsnprintf() must be preceded by va_start
and followed by va_end. And this is possible only in the function
that contains the `...' declaration. The alternative would be to
use va_copy, but that's not portable. */
static int
logvprintf (struct logvprintf_state *state, const char *fmt, va_list args)
{
CHECK_VERBOSE (o);
CANONICALIZE_LOGFP_OR_RETURN;
/* Originally, we first used vfprintf(), and then checked whether
the message needs to be stored with vsprintf(). However, Watcom
C didn't like ARGS being used twice, so now we first vsprintf()
the message, and then fwrite() it to LOGFP. */
char smallmsg[128];
char *write_ptr = smallmsg;
int available_size = sizeof (smallmsg);
int numwritten;
if (!save_log_p)
{
/* In the simple case just call vfprintf(), to avoid needless
allocation and games with vsnprintf(). */
vfprintf (logfp, fmt, args);
goto flush;
}
else
if (state->allocated != 0)
{
char smallmsg[128];
char *bigmsg = NULL;
int available_size = sizeof (smallmsg);
char *write_ptr = smallmsg;
while (1)
{
/* The GNU coding standards advise not to rely on the return
value of sprintf(). However, vsnprintf() is a relatively
new function missing from legacy systems. Therefore it's
safe to assume that its return value is meaningful. On
the systems where vsnprintf() is not available, we use
the implementation from snprintf.c which does return the
correct value. */
int numwritten = vsnprintf (write_ptr, available_size, fmt, args);
/* vsnprintf() will not step over the limit given by
available_size. If it fails, it will return either -1
(POSIX?) or the number of characters that *would have*
been written, if there had been enough room. In the
former case, we double the available_size and malloc() to
get a larger buffer, and try again. In the latter case,
we use the returned information to build a buffer of the
correct size. */
if (numwritten == -1)
{
/* Writing failed, and we don't know the needed size.
Try again with doubled size. */
available_size <<= 1;
bigmsg = xrealloc (bigmsg, available_size);
write_ptr = bigmsg;
}
else if (numwritten >= available_size)
{
/* Writing failed, but we know exactly how much space we
need. */
available_size = numwritten + 1;
bigmsg = xrealloc (bigmsg, available_size);
write_ptr = bigmsg;
}
else
{
/* Writing succeeded. */
break;
}
}
saved_append (write_ptr);
fputs (write_ptr, logfp);
if (bigmsg)
xfree (bigmsg);
write_ptr = state->bigmsg;
available_size = state->allocated;
}
/* The GNU coding standards advise not to rely on the return value
of sprintf(). However, vsnprintf() is a relatively new function
missing from legacy systems. Therefore I consider it safe to
assume that its return value is meaningful. On the systems where
vsnprintf() is not available, we use the implementation from
snprintf.c which does return the correct value. */
numwritten = vsnprintf (write_ptr, available_size, fmt, args);
/* vsnprintf() will not step over the limit given by available_size.
If it fails, it will return either -1 (POSIX?) or the number of
characters that *would have* been written, if there had been
enough room. In the former case, we double the available_size
and malloc() to get a larger buffer, and try again. In the
latter case, we use the returned information to build a buffer of
the correct size. */
if (numwritten == -1)
{
/* Writing failed, and we don't know the needed size. Try
again with doubled size. */
int newsize = available_size << 1;
state->bigmsg = xrealloc (state->bigmsg, newsize);
state->allocated = newsize;
return 0;
}
else if (numwritten >= available_size)
{
/* Writing failed, but we know exactly how much space we
need. */
int newsize = numwritten + 1;
state->bigmsg = xrealloc (state->bigmsg, newsize);
state->allocated = newsize;
return 0;
}
/* Writing succeeded. */
saved_append (write_ptr);
fputs (write_ptr, logfp);
if (state->bigmsg)
xfree (state->bigmsg);
flush:
if (flush_log_p)
logflush ();
else
needs_flushing = 1;
return 1;
}
/* Flush LOGFP. Useful while flushing is disabled. */
@ -392,6 +400,21 @@ log_set_flush (int flush)
}
}
#ifdef WGET_USE_STDARG
# define VA_START_1(arg1_type, arg1, args) va_start(args, arg1)
# define VA_START_2(arg1_type, arg1, arg2_type, arg2, args) va_start(args, arg2)
#else /* not WGET_USE_STDARG */
# define VA_START_1(arg1_type, arg1, args) do { \
va_start (args); \
arg1 = va_arg (args, arg1_type); \
} while (0)
# define VA_START_2(arg1_type, arg1, arg2_type, arg2, args) do { \
va_start (args); \
arg1 = va_arg (args, arg1_type); \
arg2 = va_arg (args, arg2_type); \
} while (0)
#endif /* not WGET_USE_STDARG */
/* Portability with pre-ANSI compilers makes these two functions look
like @#%#@$@#$. */
@ -405,20 +428,29 @@ logprintf (va_alist)
#endif /* not WGET_USE_STDARG */
{
va_list args;
struct logvprintf_state lpstate;
int done;
#ifndef WGET_USE_STDARG
enum log_options o;
const char *fmt;
/* Perform a "dry run" of VA_START_2 to get the value of O. */
VA_START_2 (enum log_options, o, char *, fmt, args);
va_end (args);
#endif
#ifdef WGET_USE_STDARG
va_start (args, fmt);
#else
va_start (args);
o = va_arg (args, enum log_options);
fmt = va_arg (args, char *);
#endif
logvprintf (o, fmt, args);
va_end (args);
CHECK_VERBOSE (o);
CANONICALIZE_LOGFP_OR_RETURN;
memset (&lpstate, '\0', sizeof (lpstate));
do
{
VA_START_2 (enum log_options, o, char *, fmt, args);
done = logvprintf (&lpstate, fmt, args);
va_end (args);
}
while (!done);
}
#ifdef DEBUG
@ -439,15 +471,19 @@ debug_logprintf (va_alist)
#ifndef WGET_USE_STDARG
const char *fmt;
#endif
struct logvprintf_state lpstate;
int done;
#ifdef WGET_USE_STDARG
va_start (args, fmt);
#else
va_start (args);
fmt = va_arg (args, char *);
#endif
logvprintf (LOG_ALWAYS, fmt, args);
va_end (args);
CANONICALIZE_LOGFP_OR_RETURN;
memset (&lpstate, '\0', sizeof (lpstate));
do
{
VA_START_1 (char *, fmt, args);
done = logvprintf (&lpstate, fmt, args);
va_end (args);
}
while (!done);
}
}
#endif /* DEBUG */