From 42995d7bf396933ee60c5f89c354ea89cf13df0d Mon Sep 17 00:00:00 2001
From: tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>
Date: Tue, 5 Jan 2010 00:01:18 +0000
Subject: Copy of aRts for Trinity modifications

git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/dependencies/arts@1070145 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
---
 mcop/debug.cc | 821 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 821 insertions(+)
 create mode 100644 mcop/debug.cc

(limited to 'mcop/debug.cc')

diff --git a/mcop/debug.cc b/mcop/debug.cc
new file mode 100644
index 0000000..208727b
--- /dev/null
+++ b/mcop/debug.cc
@@ -0,0 +1,821 @@
+    /*
+
+    Copyright (C) 2000-2002 Stefan Westerfeld
+                            stefan@space.twc.de
+
+	(see also below for details on the copyright of arts_strdup_printf,
+	 which is taken from GLib)
+ 
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+  
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+   
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.
+
+    */
+
+#include "debug.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include "thread.h"
+
+static int arts_debug_level = Arts::Debug::lInfo;
+static bool arts_debug_abort = false;
+static const char *arts_debug_prefix = "";
+static char *messageAppName = 0;
+static Arts::Mutex *arts_debug_mutex = 0;
+
+/* routines for variable length sprintf without buffer overflow (from GLib) */
+static char* arts_strdup_vprintf(const char *format, va_list args1);
+
+namespace Arts {
+
+static char * shell_quote(const char *s)
+{
+   char *result;
+   char *p;
+   p = result = static_cast<char*>( malloc(strlen(s)*5+1) );
+   while(*s)
+   {
+     if (*s == '\'')
+     {
+        *p++ = '\'';
+        *p++ = '"';
+        *p++ = *s++;
+        *p++ = '"';
+        *p++ = '\'';
+     }
+     else
+     {
+        *p++ = *s++;
+     }
+   }
+   *p = '\0';
+   return result;
+}
+
+/*
+ * Call the graphical application to display a message, if
+ * defined. Otherwise, send to standard error. Debug messages are
+ * always sent to standard error because they tend to be very verbose.
+ * Note that the external application is run in the background to
+ * avoid blocking the sound server.
+ */
+static void output_message(Debug::Level level, const char *msg) {
+	char *quoted_msg;
+	char *buff = 0;
+
+	/* default to text output if no message app is defined or if it is a debug message. */
+	if (messageAppName == 0 || !strcmp(messageAppName, "") || (level == Debug::lDebug))
+	{
+		fprintf(stderr, "%s\n", msg);
+		return;
+	}
+
+        quoted_msg = shell_quote(msg);
+	switch (level) {
+	  case Debug::lFatal:
+		  buff = arts_strdup_printf("%s -e 'Sound server fatal error:\n\n%s' &", messageAppName, quoted_msg);
+		  break;
+	  case Debug::lWarning:
+		  buff = arts_strdup_printf("%s -w 'Sound server warning message:\n\n%s' &", messageAppName, quoted_msg);
+		  break;
+	  case Debug::lInfo:
+		  buff = arts_strdup_printf("%s -i 'Sound server informational message:\n\n%s' &", messageAppName, quoted_msg);
+		  break;
+	  default:
+		  break; // avoid compile warning
+	}
+	free(quoted_msg);
+	
+	if(buff != 0)
+	{
+		system(buff);
+		free(buff);
+	}
+}
+
+/*
+ * Display a message using output_message. If the message is the same
+ * as the previous one, just increment a count but don't display
+ * it. This prevents flooding the user with duplicate warnings. If the
+ * message is not the same as the previous one, then we report the
+ * previously repeated message (if any) and reset the last message and
+ * count.
+ */
+static void display_message(Debug::Level level, const char *msg) {
+	static char lastMsg[1024];
+	static Debug::Level lastLevel;
+	static int msgCount = 0;
+
+	if(arts_debug_mutex)
+		arts_debug_mutex->lock();
+
+	if (!strncmp(msg, lastMsg, 1024))
+	{
+		msgCount++;
+	} else {
+		if (msgCount > 0)
+		{
+			char *buff;
+			buff = arts_strdup_printf("%s\n(The previous message was repeated %d times.)", lastMsg, msgCount);
+			output_message(lastLevel, buff);
+			free(buff);
+		}
+		strncpy(lastMsg, msg, 1024);
+                lastMsg[ 1023 ] = '\0';
+		lastLevel = level;
+		msgCount = 0;
+		output_message(level, msg);
+	}
+
+	if(arts_debug_mutex)
+		arts_debug_mutex->unlock();
+}
+
+static class DebugInitFromEnv {
+public:
+	DebugInitFromEnv() {
+		const char *env = getenv("ARTS_DEBUG");
+		if(env)
+		{
+			if(strcmp(env,"debug") == 0)
+				arts_debug_level = Debug::lDebug;
+			else if(strcmp(env,"info") == 0)
+				arts_debug_level = Debug::lInfo;
+			else if(strcmp(env,"warning") == 0)
+				arts_debug_level = Debug::lWarning;
+			else if(strcmp(env,"quiet") == 0)
+				arts_debug_level = Debug::lFatal;
+			else
+			{
+				fprintf(stderr,
+					"ARTS_DEBUG must be one of debug,info,warning,quiet\n");
+			}
+		}
+		env = getenv("ARTS_DEBUG_ABORT");
+		if(env)
+			arts_debug_abort = true;
+	}
+} debugInitFromEnv;
+
+}
+
+void Arts::Debug::init(const char *prefix, Level level)
+{
+	arts_debug_level = level;
+	arts_debug_prefix = prefix;
+}
+
+void Arts::Debug::fatal(const char *fmt, ...)
+{
+	char *buff;
+    va_list ap;
+
+    va_start(ap, fmt);
+	buff = arts_strdup_vprintf(fmt, ap);
+    va_end(ap);
+
+	display_message(Debug::lFatal, buff);
+	free(buff);
+
+	if(arts_debug_abort) abort();
+	exit(1);
+}
+
+void Arts::Debug::warning(const char *fmt, ...)
+{
+	if(lWarning >= arts_debug_level)
+	{
+		char *buff;
+		va_list ap;
+
+		va_start(ap, fmt);
+		buff = arts_strdup_vprintf(fmt, ap);
+		va_end(ap);
+
+		display_message(Debug::lWarning, buff);
+		free(buff);
+	}
+}
+
+void Arts::Debug::info(const char *fmt, ...)
+{
+	if(lInfo >= arts_debug_level)
+	{
+		char *buff;
+		va_list ap;
+
+		va_start(ap, fmt);
+		buff = arts_strdup_vprintf(fmt, ap);
+		va_end(ap);
+
+		display_message(Debug::lInfo, buff);
+		free(buff);
+	}
+}
+
+void Arts::Debug::debug(const char *fmt, ...)
+{
+	if(lDebug >= arts_debug_level)
+	{
+		char *buff;
+		va_list ap;
+
+		va_start(ap, fmt);
+		buff = arts_strdup_vprintf(fmt, ap);
+		va_end(ap);
+
+		display_message(Debug::lDebug, buff);
+		free(buff);
+	}
+}
+
+void Arts::Debug::messageApp(const char *appName)
+{
+	messageAppName = (char*) realloc(messageAppName, strlen(appName)+1);
+	strcpy(messageAppName, appName);
+}
+
+void Arts::Debug::initMutex()
+{
+	arts_return_if_fail(arts_debug_mutex == 0);
+
+	arts_debug_mutex = new Arts::Mutex();
+}
+
+void Arts::Debug::freeMutex()
+{
+	arts_return_if_fail(arts_debug_mutex != 0);
+
+	delete arts_debug_mutex;
+	arts_debug_mutex = 0;
+}
+
+/*
+ * For the sake of portability (snprintf is non-portable), what follows is an
+ * implementation of a variant g_strdup_printf, to format debug messages of
+ * an arbitary length appropriately. This is reduntant with flow/gsl/gslglib.c,
+ * however, as libmcop doesn't necessarily link against gslglib.c, this is a
+ * more-or-less complete copy.
+ */
+
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * GScanner: Flexible lexical scanner for general purpose.
+ * Copyright (C) 1997, 1998 Tim Janik
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GLib Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+
+#define g_warning printf
+#define g_strerror strerror
+
+/*--- gslglib.h ---*/
+
+#include <limits.h>
+#include <float.h>
+#include <stddef.h>
+#include <stdarg.h>
+
+/* --- GLib typedefs --- */
+typedef void*           gpointer;
+typedef const void*     gconstpointer;
+typedef char            gchar;
+typedef unsigned char   guchar;
+typedef signed short    gshort;
+typedef unsigned short  gushort;
+typedef signed int      gint;
+typedef unsigned int    guint;
+typedef signed long     glong;
+typedef unsigned long   gulong;
+typedef float           gfloat;
+typedef double          gdouble;
+typedef size_t          gsize;
+typedef gchar           gint8;
+typedef guchar          guint8;
+typedef gshort          gint16;
+typedef gushort         guint16;
+typedef gint            gint32;
+typedef guint           guint32;
+typedef gint            gboolean;
+typedef gint32          GTime;
+#ifdef __alpha
+typedef long int                gint64;
+typedef unsigned long int       guint64;
+#else
+typedef long long int   gint64;
+typedef unsigned long long int  guint64;
+#endif
+typedef struct _GString GString;
+
+/* --- standard macros --- */
+#ifndef ABS
+#define ABS(a)          ((a) > 0 ? (a) : -(a))
+#endif
+#ifndef MAX
+#define MAX(a,b)        ((a) > (b) ? (a) : (b))
+#endif
+#ifndef MIN
+#define MIN(a,b)        ((a) < (b) ? (a) : (b))
+#endif
+#ifndef CLAMP
+#define CLAMP(v,l,h)    ((v) < (l) ? (l) : (v) > (h) ? (h) : (v))
+#endif
+#ifndef FALSE
+#define FALSE           0
+#endif
+#ifndef TRUE
+#define TRUE            (!FALSE)
+#endif
+#ifndef NULL
+#define NULL            ((void*) 0)
+#endif
+
+/* --- configure stuff!!! --- */
+#ifdef WORDS_BIGENDIAN
+#define G_BYTE_ORDER G_BIG_ENDIAN
+#else
+#define G_BYTE_ORDER G_LITTLE_ENDIAN
+#endif
+
+/* #define      GLIB_HAVE_STPCPY        1 */
+/* Define G_VA_COPY() to do the right thing for copying va_list variables.
+ * glibconfig.h may have already defined G_VA_COPY as va_copy or __va_copy.
+ */
+#if !defined (G_VA_COPY)
+#  if defined (__GNUC__) && defined (__PPC__) && (defined (_CALL_SYSV) || defined (_WIN32) || defined(WIN32)) || defined(__s390__) || defined(__x86_64__)
+#    define G_VA_COPY(ap1, ap2)   (*(ap1) = *(ap2))
+#  elif defined (G_VA_COPY_AS_ARRAY)
+#    define G_VA_COPY(ap1, ap2)   g_memmove ((ap1), (ap2), sizeof (va_list))
+#  else /* va_list is a pointer */
+#    define G_VA_COPY(ap1, ap2)   ((ap1) = (ap2))
+#  endif /* va_list is a pointer */
+#endif /* !G_VA_COPY */
+
+/* --- glib macros --- */
+#define G_MINFLOAT      FLT_MIN
+#define G_MAXFLOAT      FLT_MAX
+#define G_MINDOUBLE     DBL_MIN
+#define G_MAXDOUBLE     DBL_MAX
+#define G_MINSHORT      SHRT_MIN
+#define G_MAXSHORT      SHRT_MAX
+#define G_MAXUSHORT     USHRT_MAX
+#define G_MININT        INT_MIN
+#define G_MAXINT        INT_MAX
+#define G_MAXUINT       UINT_MAX
+#define G_MINLONG       LONG_MIN
+#define G_MAXLONG       LONG_MAX
+#define G_MAXULONG      ULONG_MAX
+#define G_USEC_PER_SEC  1000000
+#define G_LITTLE_ENDIAN 1234
+#define G_BIG_ENDIAN    4321
+
+#define G_STRINGIFY(macro_or_string)    G_STRINGIFY_ARG (macro_or_string)
+#define G_STRINGIFY_ARG(contents)       #contents
+#if  defined __GNUC__ && !defined __cplusplus
+#  define G_STRLOC      __FILE__ ":" G_STRINGIFY (__LINE__) ":" __PRETTY_FUNCTION__ "()"
+#else
+#  define G_STRLOC      __FILE__ ":" G_STRINGIFY (__LINE__)
+#endif
+       
+/* subtract from biased_exponent to form base2 exponent (normal numbers) */
+typedef union  _GDoubleIEEE754  GDoubleIEEE754;
+typedef union  _GFloatIEEE754   GFloatIEEE754;
+#define G_IEEE754_FLOAT_BIAS    (127)
+#define G_IEEE754_DOUBLE_BIAS   (1023)
+/* multiply with base2 exponent to get base10 exponent (nomal numbers) */
+#define G_LOG_2_BASE_10         (0.30102999566398119521)
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+union _GFloatIEEE754
+{
+  gfloat v_float;
+  struct {
+    guint mantissa : 23;
+    guint biased_exponent : 8;
+    guint sign : 1;
+  } mpn;
+};
+union _GDoubleIEEE754
+{
+  gdouble v_double;
+  struct {
+    guint mantissa_low : 32;
+    guint mantissa_high : 20;
+    guint biased_exponent : 11;
+    guint sign : 1;
+  } mpn;
+};
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+union _GFloatIEEE754
+{
+  gfloat v_float;
+  struct {
+    guint sign : 1;
+    guint biased_exponent : 8;
+    guint mantissa : 23;
+  } mpn;
+};
+union _GDoubleIEEE754
+{
+  gdouble v_double;
+  struct {
+    guint sign : 1;
+    guint biased_exponent : 11;
+    guint mantissa_high : 20;
+    guint mantissa_low : 32;
+  } mpn;
+};
+#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
+#error unknown ENDIAN type
+#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#define GLIB_SIZEOF_INTMAX      (8 /* educated guess */)
+
+typedef struct
+{
+  guint min_width;
+  guint precision;
+  gboolean alternate_format, zero_padding, adjust_left, locale_grouping;
+  gboolean add_space, add_sign, possible_sign, seen_precision;
+  gboolean mod_half, mod_long, mod_extra_long;
+} PrintfArgSpec;
+
+
+static gsize
+printf_string_upper_bound (const gchar *format,
+                           gboolean     may_warn,
+                           va_list      args)
+{
+  static  gboolean honour_longs = sizeof(long) > 4 || sizeof(void*) > 4;
+  gsize len = 1;
+
+  if (!format)
+    return len;
+
+  while (*format)
+    {
+      register gchar c = *format++;
+
+      if (c != '%')
+        len += 1;
+      else /* (c == '%') */
+        {
+          PrintfArgSpec spec = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+          gboolean seen_l = FALSE, conv_done = FALSE;
+          gsize conv_len = 0;
+          const gchar *spec_start = format;
+
+          do
+            {
+              c = *format++;
+              switch (c)
+                {
+                  GDoubleIEEE754 u_double;
+                  guint v_uint;
+                  gint v_int;
+                  const gchar *v_string;
+
+                  /* beware of positional parameters
+                   */
+                case '$':
+                  if (may_warn)
+                    g_warning (G_STRLOC ": unable to handle positional parameters (%%n$)");
+                  len += 1024; /* try adding some safety padding */
+                  break;
+
+                  /* parse flags
+                   */
+                case '#':
+                  spec.alternate_format = TRUE;
+                  break;
+                case '0':
+                  spec.zero_padding = TRUE;
+                  break;
+                case '-':
+                  spec.adjust_left = TRUE;
+                  break;
+                case ' ':
+                  spec.add_space = TRUE;
+                  break;
+                case '+':
+                  spec.add_sign = TRUE;
+                  break;
+                case '\'':
+                  spec.locale_grouping = TRUE;
+                  break;
+
+                  /* parse output size specifications
+                   */
+                case '.':
+                  spec.seen_precision = TRUE;
+                  break;
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+                  v_uint = c - '0';
+                  c = *format;
+                  while (c >= '0' && c <= '9')
+                    {
+                      format++;
+                      v_uint = v_uint * 10 + c - '0';
+                      c = *format;
+                    }
+                  if (spec.seen_precision)
+                    spec.precision = MAX (spec.precision, v_uint);
+                  else
+                    spec.min_width = MAX (spec.min_width, v_uint);
+                  break;
+                case '*':
+                  v_int = va_arg (args, int);
+                  if (spec.seen_precision)
+                    {
+                      /* forget about negative precision */
+                      if (v_int >= 0)
+                        spec.precision = MAX (spec.precision, (unsigned)v_int);
+                    }
+                  else
+                    {
+                      if (v_int < 0)
+                        {
+                          v_int = - v_int;
+                          spec.adjust_left = TRUE;
+                        }
+                      spec.min_width = MAX (spec.min_width, (unsigned)v_int);
+                    }
+                  break;
+
+                  /* parse type modifiers
+                   */
+                case 'h':
+                  spec.mod_half = TRUE;
+                  break;
+                case 'l':
+                  if (!seen_l)
+                    {
+                      spec.mod_long = TRUE;
+                      seen_l = TRUE;
+                      break;
+                    }
+                  /* else, fall through */
+                case 'L':
+                case 'q':
+                  spec.mod_long = TRUE;
+                  spec.mod_extra_long = TRUE;
+                  break;
+                case 'z':
+                case 'Z':
+                  if (sizeof(size_t))
+                    {
+                      spec.mod_long = TRUE;
+                      spec.mod_extra_long = TRUE;
+                    }
+                  break;
+                case 't':
+                  if (sizeof(ptrdiff_t) > 4)
+                    {
+                      spec.mod_long = TRUE;
+                      spec.mod_extra_long = TRUE;
+                    }
+                  break;
+                case 'j':
+                  if (GLIB_SIZEOF_INTMAX > 4)
+                    {
+                      spec.mod_long = TRUE;
+                      spec.mod_extra_long = TRUE;
+                    }
+                  break;
+
+                  /* parse output conversions
+                   */
+                case '%':
+                  conv_len += 1;
+                  break;
+                case 'O':
+                case 'D':
+                case 'I':
+                case 'U':
+                  /* some C libraries feature long variants for these as well? */
+                  spec.mod_long = TRUE;
+                  /* fall through */
+                case 'o':
+                  conv_len += 2;
+                  /* fall through */
+                case 'd':
+                case 'i':
+                  conv_len += 1; /* sign */
+                  /* fall through */
+                case 'u':
+                  conv_len += 4;
+                  /* fall through */
+                case 'x':
+                case 'X':
+                  spec.possible_sign = TRUE;
+                  conv_len += 10;
+                  if (spec.mod_long && honour_longs)
+                    conv_len *= 2;
+                  if (spec.mod_extra_long)
+                    conv_len *= 2;
+                  if (spec.mod_extra_long)
+                    {
+                      (void) va_arg (args, gint64);
+                    }
+                  else if (spec.mod_long)
+                    (void) va_arg (args, long);
+                  else
+                    (void) va_arg (args, int);
+                  break;
+                case 'A':
+                case 'a':
+                  /*          0x */
+                  conv_len += 2;
+                  /* fall through */
+                case 'g':
+                case 'G':
+                case 'e':
+                case 'E':
+                case 'f':
+                  spec.possible_sign = TRUE;
+                  /*          n   .   dddddddddddddddddddddddd   E   +-  eeee */
+                  conv_len += 1 + 1 + MAX (24, spec.precision) + 1 + 1 + 4;
+                  if (may_warn && spec.mod_extra_long)
+                    g_warning (G_STRLOC ": unable to handle long double, collecting double only");
+#ifdef HAVE_LONG_DOUBLE
+#error need to implement special handling for long double
+#endif
+                  u_double.v_double = va_arg (args, double);
+                  /* %f can expand up to all significant digits before '.' (308) */
+                  if (c == 'f' &&
+                      u_double.mpn.biased_exponent > 0 && u_double.mpn.biased_exponent < 2047)
+                    {
+                      gint exp = u_double.mpn.biased_exponent;
+
+                      exp -= G_IEEE754_DOUBLE_BIAS;
+                      exp = (gint)(exp * G_LOG_2_BASE_10 + 1);
+                      conv_len += ABS (exp);    /* exp can be <0 */
+                    }
+                  /* some printf() implementations require extra padding for rounding */
+                  conv_len += 2;
+                  /* we can't really handle locale specific grouping here */
+                  if (spec.locale_grouping)
+                    conv_len *= 2;
+                  break;
+                case 'C':
+                  spec.mod_long = TRUE;
+                  /* fall through */
+                case 'c':
+                  conv_len += spec.mod_long ? MB_LEN_MAX : 1;
+                  (void) va_arg (args, int);
+                  break;
+                case 'S':
+                  spec.mod_long = TRUE;
+                  /* fall through */
+                case 's':
+                  v_string = va_arg (args, char*);
+                  if (!v_string)
+                    conv_len += 8; /* hold "(null)" */
+                  else if (spec.seen_precision)
+                    conv_len += spec.precision;
+                  else
+                    conv_len += strlen (v_string);
+                  conv_done = TRUE;
+                  if (spec.mod_long)
+                    {
+                      if (may_warn)
+                        g_warning (G_STRLOC": unable to handle wide char strings");
+                      len += 1024; /* try adding some safety padding */
+                    }
+                  break;
+                case 'P': /* do we actually need this? */
+                  /* fall through */
+                case 'p':
+                  spec.alternate_format = TRUE;
+                  conv_len += 10;
+                  if (honour_longs)
+                    conv_len *= 2;
+                  /* fall through */
+                case 'n':
+                  conv_done = TRUE;
+                  (void) va_arg (args, void*);
+                  break;
+                case 'm':
+                  /* there's not much we can do to be clever */
+                  v_string = g_strerror (errno);
+                  v_uint = v_string ? strlen (v_string) : 0;
+                  conv_len += MAX (256, v_uint);
+                  break;
+
+                  /* handle invalid cases
+                   */
+                case '\000':
+                  /* no conversion specification, bad bad */
+                  conv_len += format - spec_start;
+                  break;
+                default:
+                  if (may_warn)
+                    g_warning (G_STRLOC": unable to handle `%c' while parsing format",
+                               c);
+                  break;
+                }
+              conv_done |= conv_len > 0;
+            }
+          while (!conv_done);
+          /* handle width specifications */
+          conv_len = MAX (conv_len, MAX (spec.precision, spec.min_width));
+          /* handle flags */
+          conv_len += spec.alternate_format ? 2 : 0;
+          conv_len += (spec.add_space || spec.add_sign || spec.possible_sign);
+          /* finally done */
+          len += conv_len;
+        } /* else (c == '%') */
+    } /* while (*format) */
+
+  return len;
+}
+
+static char*
+#ifdef __GNUC__
+__attribute__ ( (format (printf, 1, 0) ) )
+#endif
+arts_strdup_vprintf (const char *format, va_list args1)
+{
+  gchar *buffer;
+#ifdef HAVE_VASPRINTF
+  if (vasprintf (&buffer, format, args1) < 0)
+    buffer = NULL;
+#else
+  va_list args2;
+
+  G_VA_COPY (args2, args1);
+
+  buffer = (gchar *)malloc (printf_string_upper_bound (format, TRUE, args1));
+
+  vsprintf (buffer, format, args2);
+  va_end (args2);
+#endif
+  return buffer;
+}
+
+char*
+#ifdef __GNUC__
+__attribute__ ( (format (printf, 1, 0) ) )
+#endif
+arts_strdup_printf (const char *format, ...)
+{
+  gchar *buffer;
+  va_list args;
+
+  va_start (args, format);
+  buffer = arts_strdup_vprintf (format, args);
+  va_end (args);
+
+  return buffer;
+}
-- 
cgit v1.2.1