+
+/* Build an report message by appending MESSAGE, which is a printf-style
+ format string with optional args, to the existing report message (which may
+ be empty.) The completed report message is finally printed (and reset to
+ empty) by calling report_complete().
+ If an intervening call to report() occurs when a partially constructed
+ message exists, then, in an attempt to keep the messages in their proper
+ sequence, the partial message will be printed as-is (with a trailing
+ newline) before report() prints its message. */
+/* VARARGS */
+
+static void rep_ensuresize(void) {
+ /* Make an initial guess for the size of any single message fragment. */
+ if (partial_message_size == 0)
+ {
+ partial_message_size_used = 0;
+ partial_message_size = 2048;
+ partial_message = (char *)MALLOC (partial_message_size);
+ }
+ else
+ if (partial_message_size - partial_message_size_used < 1024)
+ {
+ partial_message_size += 2048;
+ partial_message = (char *)REALLOC (partial_message, partial_message_size);
+ }
+}
+
+#ifdef HAVE_STDARG_H
+static void report_vbuild(const char *message, va_list args)
+{
+ int n;
+
+ for ( ; ; )
+ {
+ /*
+ * args has to be initialized before every call of vsnprintf(),
+ * because vsnprintf() invokes va_arg macro and thus args is
+ * undefined after the call.
+ */
+ n = vsnprintf (partial_message + partial_message_size_used, partial_message_size - partial_message_size_used,
+ message, args);
+
+ /* output error, f. i. EILSEQ */
+ if (n < 0) break;
+
+ if (n >= 0
+ && (unsigned)n < partial_message_size - partial_message_size_used)
+ {
+ partial_message_size_used += n;
+ break;
+ }
+
+ partial_message_size += 2048;
+ partial_message = (char *)REALLOC (partial_message, partial_message_size);
+ }
+}
+#endif
+
+void
+#ifdef HAVE_STDARG_H
+report_build (FILE *errfp, const char *message, ...)
+#else
+report_build (FILE *errfp, message, va_alist)
+ const char *message;
+ va_dcl
+#endif
+{
+#ifdef VA_START
+ va_list args;
+#else
+ int n;
+#endif
+
+ rep_ensuresize();
+
+#if defined(VA_START)
+ VA_START(args, message);
+ report_vbuild(message, args);
+ va_end(args);
+#else
+ for ( ; ; )
+ {
+ n = snprintf (partial_message + partial_message_size_used,
+ partial_message_size - partial_message_size_used,
+ message, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ /* output error, f. i. EILSEQ */
+ if (n < 0) break;
+
+ if (n >= 0
+ && (unsigned)n < partial_message_size - partial_message_size_used)
+ {
+ partial_message_size_used += n;
+ break;
+ }
+
+ partial_message_size += 2048;
+ partial_message = REALLOC (partial_message, partial_message_size);
+ }
+#endif
+
+ if (unbuffered && partial_message_size_used != 0)
+ {
+ partial_message_size_used = 0;
+ fputs(partial_message, errfp);
+ }
+}
+
+void report_flush(FILE *errfp)
+{
+ if (partial_message_size_used != 0)
+ {
+ partial_message_size_used = 0;
+ report(errfp, "%s", partial_message);
+ partial_suppress_tag = 1;
+ }
+}
+
+/* Complete a report message by appending MESSAGE, which is a printf-style
+ format string with optional args, to the existing report message (which may
+ be empty.) The completed report message is then printed (and reset to
+ empty.) */
+/* VARARGS */
+void
+#ifdef HAVE_STDARG_H
+report_complete (FILE *errfp, const char *message, ...)
+#else
+report_complete (FILE *errfp, message, va_alist)
+ const char *message;
+ va_dcl
+#endif
+{
+#ifdef VA_START
+ va_list args;
+#endif
+
+ rep_ensuresize();
+
+#if defined(VA_START)
+ VA_START(args, message);
+ report_vbuild(message, args);
+ va_end(args);
+#else
+ report_build(errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
+
+ /* Finally... print it. */
+ partial_message_size_used = 0;
+
+ if (unbuffered)
+ {
+ fputs(partial_message, errfp);
+ fflush (errfp);
+ }
+ else
+ report(errfp, "%s", partial_message);
+}
+