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)
-{
- CHECK_VERBOSE (o);
- CANONICALIZE_LOGFP_OR_RETURN;
+ 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. */
- /* 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. */
+static int
+logvprintf (struct logvprintf_state *state, const char *fmt, va_list args)
+{
+ 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;
+ write_ptr = state->bigmsg;
+ available_size = state->allocated;
+ }
- 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);
+ /* 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. */
}
}
+#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 @#%#@$@#$. */
#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;
-#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);
+ /* 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
+
+ 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
#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 */