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:
parent
fcf68c0e9a
commit
f8e6feb6bc
@ -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
194
src/log.c
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user