OSDN Git Service

Improve ISO-C conformity in MinGW printf(); cf. MinGW-Bug [#1761]
authorKeith Marshall <keithmarshall@users.sourceforge.net>
Sun, 27 Dec 2015 12:26:00 +0000 (12:26 +0000)
committerKeith Marshall <keithmarshall@users.sourceforge.net>
Sun, 27 Dec 2015 12:26:00 +0000 (12:26 +0000)
mingwrt/ChangeLog
mingwrt/Makefile.in
mingwrt/include/stdio.h
mingwrt/mingwex/ofmt.c
mingwrt/mingwex/ofmtctl.c [new file with mode: 0644]
mingwrt/mingwex/stdio/pformat.c

index 09e6c59..0c7350d 100644 (file)
@@ -1,3 +1,33 @@
+2015-12-27  Keith Marshall  <keithmarshall@users.sourceforge.net>
+
+       Improve ISO-C conformity in MinGW printf(); cf. MinGW-Bug [#1761]
+
+       * mingwex/ofmtctl.c: New file; it implements...
+       (_mingw_output_format_control): ...this new function; it provides
+       additional MinGW specific printf() format processing options.
+
+       * Makefile.in (libmingwex.a) [prerequisites]: Add ofmtctl.$OBJEXT
+
+       * include/stdio.h (_mingw_output_format_control): Declare it.
+       (_EXPONENT_DIGIT_MASK, _MSVC_PRINTF_QUIRKS, _QUERY_MSVC_PRINTF_QUIRKS)
+       (_ENABLE_MSVC_PRINTF_QUIRKS, _DISABLE_MSVC_PRINTF_QUIRKS): New
+       manifest constant expressions; define them.
+
+       * mingwex/stdio/pformat.c: Revise licensing terms.
+       (__pformat) [%le, %lE, %lf, %lF, %lg, %lG, %lx, %lX]: When...
+       [_mingw_output_format_flag & _MSVC_PRINTF_QUIRKS == 0]: ...ignore `l'
+       modifier; this matches the behaviour specified by ISO-C99, else...
+       [_mingw_output_format_flag & _MSVC_PRINTF_QUIRKS != 0]: ...revert to
+       previous MSVC compatible behaviour, treating it as an `L' modifier.
+       [!_WIN32] (_MSVC_PRINTF_QUIRKS): Force the zero match case.
+
+       * mingwex/ofmt.c (ARGLIST): Subsume references to...
+       (ARGTYPE): ...this now obsolete macro; delete it throughout.
+       (update_output_format_flag): New inline function; it restricts flag
+       operations to affect only Microsoft's exponent digit bits.
+       [FUNCTION == _set_output_format]: Use it.
+       [FUNCTION == _get_output_format]: Likewise.
+
 2015-10-23  Keith Marshall  <keithmarshall@users.sourceforge.net>
 
        Make atof() and strtod() conform to ISO-C; fix MinGW-Bug [#2273]
index 0f7c3b0..55afdb3 100644 (file)
@@ -430,9 +430,9 @@ libmingwex.a: $(addsuffix .$(OBJEXT), cosf cosl acosf acosl sinf sinl asinf \
 # compatibility than their Microsoft equivalents.
 #
 vpath %.c ${mingwrt_srcdir}/mingwex/stdio
-libmingwex.a: $(addsuffix .$(OBJEXT), btowc fprintf fseeko64 pformat \
-  printf snprintf snwprintf sprintf vfprintf vfscanf vfwscanf vprintf \
-  vscanf vsnprintf vsnwprintf vsprintf vsscanf vswscanf vwscanf)
+libmingwex.a: $(addsuffix .$(OBJEXT), btowc fprintf fseeko64 ofmtctl pformat \
+  printf snprintf snwprintf sprintf vfprintf vfscanf vfwscanf vprintf vscanf \
+  vsnprintf vsnwprintf vsprintf vsscanf vswscanf vwscanf)
 
 # pformat.$(OBJEXT) needs an explicit build rule, since we need to
 # specify an additional header file path.
index 02fb4df..094ebad 100644 (file)
@@ -188,11 +188,9 @@ _CRTIMP int __cdecl __MINGW_NOTHROW        unlink (const char*);
 #endif /* __STRICT_ANSI__ */
 
 _CRTIMP int __cdecl __MINGW_NOTHROW    setvbuf (FILE*, char*, int, size_t);
-
 _CRTIMP void __cdecl __MINGW_NOTHROW   setbuf (FILE*, char*);
 
-/*
- * Formatted Output
+/* Formatted Output
  *
  * MSVCRT implementations are not ANSI C99 conformant...
  * we offer these conforming alternatives from libmingwex.a
@@ -209,6 +207,33 @@ extern int __mingw_stdio_redirect__(vprintf)(const char*, __VALIST);
 extern int __mingw_stdio_redirect__(vsprintf)(char*, const char*, __VALIST);
 extern int __mingw_stdio_redirect__(vsnprintf)(char*, size_t, const char*, __VALIST);
 
+/* When using these C99 conforming alternatives, we may wish to support
+ * some of Microsoft's quirky formatting options, even when they violate
+ * strict C99 conformance.
+ */
+#define _MSVC_PRINTF_QUIRKS            0x0100U
+#define _QUERY_MSVC_PRINTF_QUIRKS      ~0U, 0U
+#define _DISABLE_MSVC_PRINTF_QUIRKS    ~_MSVC_PRINTF_QUIRKS, 0U
+#define _ENABLE_MSVC_PRINTF_QUIRKS     ~0U, _MSVC_PRINTF_QUIRKS
+
+/* Those quirks which conflict with ANSI C99 specified behaviour are
+ * disabled by default; use the following function, like this:
+ *
+ *   _mingw_output_format_control( _ENABLE_MSVC_PRINTF_QUIRKS );
+ *
+ * to enable them, like this:
+ *
+ *   state = _mingw_output_format_control( _QUERY_MSVC_PRINTF_QUIRKS )
+ *             & _MSVC_PRINTF_QUIRKS;
+ *
+ * to ascertain the currently active enabled state, or like this:
+ *
+ *   _mingw_output_format_control( _DISABLE_MSVC_PRINTF_QUIRKS );
+ *
+ * to disable them again.
+ */
+extern unsigned int _mingw_output_format_control( unsigned int, unsigned int );
+
 #if __USE_MINGW_ANSI_STDIO
 /*
  * User has expressed a preference for C99 conformance...
@@ -523,6 +548,11 @@ _CRTIMP int __cdecl __MINGW_NOTHROW        _setmaxstdio (int);
  */
 #define _THREE_DIGIT_EXPONENT  0
 
+/* Once again, unspecified by Microsoft, (and mostly redundant),
+ * it is convenient to specify a combining mask for these.
+ */
+#define _EXPONENT_DIGIT_MASK  (_TWO_DIGIT_EXPONENT | _THREE_DIGIT_EXPONENT)
+
 unsigned int __cdecl __mingw_get_output_format (void);
 unsigned int __cdecl __mingw_set_output_format (unsigned int);
 
index 5a8ccf3..9d7543e 100644 (file)
@@ -8,7 +8,7 @@
  * $Id$
  *
  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
- * Copyright (C) 2014, MinGW.org Project
+ * Copyright (C) 2014, 2015, MinGW.org Project
  *
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  */
 extern unsigned int __mingw_output_format_flag;
 
+static __inline__ __attribute__((__always_inline__))
+unsigned int update_output_format_flag( unsigned int style )
+{ return (__mingw_output_format_flag & ~_EXPONENT_DIGIT_MASK) | style; }
+
 #if defined __varofmt__
 /*
  * Here, we actually allocate the storage for recording the preferred
@@ -108,7 +112,7 @@ unsigned int __mingw_get_output_format_fallback( void )
   /* Our replacement function simply returns the current setting of
    * the assigned formatting style...
    */
-  return __mingw_output_format_flag;
+  return __mingw_output_format_flag & _EXPONENT_DIGIT_MASK;
 }
 /* ...and, in the case of _set_output_format(), we simply map the
  * requisite name to the common function implementation.
@@ -139,9 +143,8 @@ int __mingw_set_printf_count_output_fallback( int mode )
  * Here, we are wrapping the _set_printf_count_output() function...
  */
 # define RTNTYPE   int
-# define ARGTYPE   int
 # define FUNCTION _set_printf_count_output
-# define ARGLIST   mode
+# define ARGLIST   int mode
 
 #define api_helper_result api_helper( mode )
 extern int __mingw_set_printf_count_output_fallback( int );
@@ -151,9 +154,8 @@ extern int __mingw_set_printf_count_output_fallback( int );
  * ...while here, it is _get_printf_count_output().
  */
 # define RTNTYPE   int
-# define ARGTYPE   void
 # define FUNCTION _get_printf_count_output
-# define ARGLIST
+# define ARGLIST   void
 
 #define api_helper_result api_helper()
 extern int __mingw_get_printf_count_output_fallback( void );
@@ -165,8 +167,7 @@ extern int __mingw_get_printf_count_output_fallback( void );
  */
 # define RTNTYPE   unsigned int
 # define FUNCTION _set_output_format
-# define ARGTYPE   unsigned int
-# define ARGLIST   style
+# define ARGLIST   unsigned int style
 
 /* Our replacement function emulates the documented behaviour of
  * its MSVCRT counterpart, assigning a new value for the recorded
@@ -181,8 +182,8 @@ api_invoke( unsigned int (*api_helper)(unsigned int), unsigned int style )
    * to retrieve the previous value for return; thus it is able
    * to use a handler in common with _get_output_format()...
    */
-  unsigned int retval = api_helper( style );
-  __mingw_output_format_flag = style;
+  unsigned int retval = api_helper( style &= _EXPONENT_DIGIT_MASK );
+  __mingw_output_format_flag = update_output_format_flag( style );
   return retval;
 }
 /* ...while declaring its formal prototype as external.
@@ -197,10 +198,17 @@ extern unsigned int __mingw_set_output_format_fallback( unsigned int );
  */
 # define RTNTYPE   unsigned int
 # define FUNCTION _get_output_format
-# define ARGTYPE   void
-# define ARGLIST
+# define ARGLIST   void
+
+static __inline__ __attribute__((__always_inline__))
+unsigned int api_invoke( unsigned int (*api_helper)( void ) )
+{
+  unsigned int retval = api_helper();
+  __mingw_output_format_flag = update_output_format_flag( retval );
+  return retval;
+}
 
-#define api_helper_result __mingw_output_format_flag = api_helper()
+#define api_helper_result api_invoke( api_helper )
 extern unsigned int __mingw_get_output_format_fallback( void );
 #endif
 
@@ -217,11 +225,11 @@ extern unsigned int __mingw_get_output_format_fallback( void );
 #define __api_name__(FUNCTION)  __stringify__(FUNCTION)
 #define __stringify__(TEXT) #TEXT
 
-RTNTYPE __mingw_(FUNCTION)( ARGTYPE ARGLIST )
+RTNTYPE __mingw_(FUNCTION)( ARGLIST )
 {
   /* Our generic interface maps an indirect call to the API...
    */
-  static RTNTYPE (*api_helper)( ARGTYPE ARGLIST ) = NULL;
+  static RTNTYPE (*api_helper)( ARGLIST ) = NULL;
 
   /* ...such that it will prefer an MSVCRT implementation...
    */
diff --git a/mingwrt/mingwex/ofmtctl.c b/mingwrt/mingwex/ofmtctl.c
new file mode 100644 (file)
index 0000000..0728f94
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * ofmtctl.c
+ *
+ * Implementation of a MinGW.org specific helper routine, to manipulate
+ * supplementary output format control flags other than those specified
+ * for the Microsoft output format control API.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall  <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2015, MinGW.org Project.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice, this permission notice, and the following
+ * disclaimer shall be included in all copies or substantial portions of
+ * the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+
+/* MinGW uses this public symbol to represent both Microsoft's exponent
+ * digit format flag, and supplementary MinGW.org specific flags.
+ */
+extern unsigned int __mingw_output_format_flags;
+
+/* The MinGW.org specific output format flag management API function.
+ * This provides both get and set capabilities for the MinGW specified
+ * flags; it has no effect on the Microsoft specified flags; use their
+ * _get_output_format() and _set_output_format() API functions when it
+ * is desired to manipulate them.
+ */
+unsigned int _mingw_output_format_control
+( unsigned int flags_to_keep, unsigned int flags_to_set )
+{
+  /* Return value is always based on current flag state.
+   */
+  unsigned int retval = __mingw_output_format_flags;
+
+  /* Adjust flags as specified by the mask of flags to keep,
+   * and add in any extra flags to set; always keep the state
+   * of the Microsoft specified flag bits, and decline to set
+   * them to any new state.
+   */
+  __mingw_output_format_flags &= flags_to_keep | _EXPONENT_DIGIT_MASK;
+  __mingw_output_format_flags |= flags_to_set & ~_EXPONENT_DIGIT_MASK;
+
+  /* Finally, exclude the Microsoft specified bits from the
+   * state to be returned, and return the original state of
+   * the MinGW specified bits.
+   */
+  return retval & ~_EXPONENT_DIGIT_MASK;
+}
+
+/* $RCSfile$: end of file */
index c9dbf3e..75226d0 100644 (file)
@@ -1,7 +1,7 @@
 /* FIXME: to be removed one day; for now we explicitly are not
  * prepared to support the POSIX-XSI additions to the C99 standard.
  */
-#undef   WITH_XSI_FEATURES
+#undef  WITH_XSI_FEATURES
 
 /* pformat.c
  *
  * to support Microsoft's non-standard format specifications.
  *
  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2008, 2009, 2011, 2014, 2015, MinGW.org Project
  *
- * This is free software.  You may redistribute and/or modify it as you
- * see fit, without restriction of copyright.
  *
- * This software is provided "as is", in the hope that it may be useful,
- * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
- * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE.  At no
- * time will the author accept any form of liability for any damages,
- * however caused, resulting from the use of this software.
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice, this permission notice, and the following
+ * disclaimer shall be included in all copies or substantial portions of
+ * the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER
+ * DEALINGS IN THE SOFTWARE.
  *
  * The elements of this implementation which deal with the formatting
  * of floating point numbers, (i.e. the `%e', `%E', `%f', `%F', `%g'
@@ -2217,25 +2229,42 @@ int __pformat( int flags, void *dest, int max, const char *fmt, va_list argv )
               */
              ++fmt;
              length = PFORMAT_LENGTH_LLONG;
+             state = PFORMAT_END;
+             break;
            }
 
            else
-             /* Modifier is `l'; data type is `long' sized...
+           { /* Modifier is `l'; data type is `long' sized...
               */
              length = PFORMAT_LENGTH_LONG;
 
-#           ifndef _WIN32
-             /*
-              * Microsoft's MSVCRT implementation also uses `l'
-              * as a modifier for `long double'; if we don't want
-              * to support that, we end this case here...
+             /* Microsoft's MSVCRT implementation also uses `l'
+              * as a modifier for `long double'; however, this
+              * conflicts with the usage specified by ISO-C and
+              * POSIX, so we definitely shouldn't support this
+              * anomaly for non-Windows builds...
               */
-             state = PFORMAT_END;
-             break;
-
-             /* otherwise, we simply fall through...
+#            ifndef _WIN32
+#              undef  _MSVC_PRINTF_QUIRKS
+#              define _MSVC_PRINTF_QUIRKS  0
+#            endif
+             /* ...nor should we support it by default, even in
+              * Windows builds, but we grant the user a mechanism
+              * to enable it via __mingw_output_format_flag.
+              */
+             if( (__mingw_output_format_flag & _MSVC_PRINTF_QUIRKS) == 0 )
+             {
+               /* When support for this Microsoft anomaly is NOT
+                * enabled, we must end this case right here...
+                */
+               state = PFORMAT_END;
+               break;
+             }
+             /* ...otherwise, we simply fall through, considering
+              * the `l' modifier as equivalent to `L`, in the case
+              * of floating point formats...
               */
-#          endif
+           }
 
          case 'L':
            /*