diff dmd/root.c @ 846:bc982f1ad106

Merged DMD 1.037 frontend
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Sat, 13 Dec 2008 13:15:31 +0100
parents fa306ca8843b
children aa953cc960b6
line wrap: on
line diff
--- a/dmd/root.c	Sat Dec 13 06:48:00 2008 +0100
+++ b/dmd/root.c	Sat Dec 13 13:15:31 2008 +0100
@@ -16,6 +16,7 @@
 
 #if _MSC_VER ||__MINGW32__
 #include <malloc.h>
+#include <string>
 #endif
 
 #if _WIN32
@@ -47,6 +48,7 @@
 }
 #endif
 
+
 /*************************************
  * Convert wchar string to ascii string.
  */
@@ -1606,6 +1608,36 @@
     fill0(nbytes);
 }
 
+
+////////////////////////////////////////////////////////////////
+// The compiler shipped with Visual Studio 2005 (and possible
+// other versions) does not support C99 printf format specfiers
+// such as %z and %j
+#if _MSC_VER
+using std::string;
+using std::wstring;
+
+template<typename S>
+inline void 
+search_and_replace(S& str, const S& what, const S& replacement)
+{
+    assert(!what.empty());
+    size_t pos = str.find(what);
+    while (pos != S::npos) 
+    {
+        str.replace(pos, what.size(), replacement);
+        pos = str.find(what, pos + replacement.size());
+    }
+}
+#define WORKAROUND_C99_SPECIFIERS_BUG(S,tmp,f) \
+    S tmp = f;                                 \
+    search_and_replace(fmt, S("%z"), S("%l")); \
+    search_and_replace(fmt, S("%j"), S("%i")); \
+    f = tmp.c_str();
+#else
+#define WORKAROUND_C99_SPECIFIERS_BUG(S,tmp,f)
+#endif
+
 void OutBuffer::vprintf(const char *format, va_list args)
 {
     char buffer[128];
@@ -1613,10 +1645,7 @@
     unsigned psize;
     int count;
 
-    // On some platforms (i.e. x86_64) va_list is an array and thus passed by
-    // reference. Copy the input list so we can copy it back before retrying.
-    va_list orig_args;
-    va_copy(orig_args, args);
+    WORKAROUND_C99_SPECIFIERS_BUG(string, fmt, format);
 
     p = buffer;
     psize = sizeof(buffer);
@@ -1628,7 +1657,19 @@
 	    break;
 	psize *= 2;
 #elif POSIX
-	count = vsnprintf(p,psize,format,args);
+        va_list va;
+        va_copy(va, args);
+/*
+  The functions vprintf(), vfprintf(), vsprintf(), vsnprintf()
+  are equivalent to the functions printf(), fprintf(), sprintf(),
+  snprintf(), respectively, except that they are called with a
+  va_list instead of a variable number of arguments. These
+  functions do not call the va_end macro. Consequently, the value
+  of ap is undefined after the call. The application should call
+  va_end(ap) itself afterwards.
+ */
+	count = vsnprintf(p,psize,format,va);
+        va_end(va);
 	if (count == -1)
 	    psize *= 2;
 	else if (count >= psize)
@@ -1636,7 +1677,6 @@
 	else
 	    break;
 #endif
-	va_copy(args, orig_args);
 	p = (char *) alloca(psize);	// buffer too small, try again with larger size
     }
     write(p,count);
@@ -1650,6 +1690,8 @@
     unsigned psize;
     int count;
 
+    WORKAROUND_C99_SPECIFIERS_BUG(wstring, fmt, format);
+
     p = buffer;
     psize = sizeof(buffer) / sizeof(buffer[0]);
     for (;;)
@@ -1661,7 +1703,11 @@
 	psize *= 2;
 #endif
 #if POSIX
-	count = vsnwprintf(p,psize,format,args);
+        va_list va;
+        va_copy(va, args);
+	count = vsnwprintf(p,psize,format,va);
+        va_end(va); 
+
 	if (count == -1)
 	    psize *= 2;
 	else if (count >= psize)