OSDN Git Service

Avoid built-in snprintf() prototypes; fix MinGW-Bug #39224
[mingw/mingw-org-wsl.git] / mingwrt / include / stdio.h
index 252c210..8ee3624 100644 (file)
@@ -7,7 +7,7 @@
  * $Id$
  *
  * Written by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
- * Copyright (C) 1997-2005, 2007-2010, 2014-2016, MinGW.org Project.
+ * Copyright (C) 1997-2005, 2007-2010, 2014-2019, MinGW.org Project.
  *
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -44,8 +44,7 @@
  * this partial fashion...
  */
 #ifndef __WCHAR_H_SOURCED__
- /*
-  * ...which is exclusive to <wchar.h>, do we assert the multiple
+ /* ...which is exclusive to <wchar.h>, do we assert the multiple
   * inclusion guard for <stdio.h> itself.
   */
 #define _STDIO_H
 # define __need_off_t
 # define __need_ssize_t
 #endif
-#if !(defined __STRICT_ANSI__ || defined (__NO_MINGW_LFS)) \
- && defined (__MSVCRT__)
- /* ...while this is required to support our fseeko64() and ftello64()
-  * implementations, (neither of which is in any way standardized)...
+
+/* Although non-standard themselves, we also need either one or other
+ * of the following pair of data types, from <sys/types.h>, because our
+ * standard fpos_t is opaquely defined in terms of...
+ */
+#ifdef __MSVCRT__
+ /* ...an explicitly 64-bit file offset type, for MSVCRT.DLL users...
   */
 # define __need___off64_t
-#endif
-/* It is sufficient to test for just one define from each of the two
- * preceding groups...
- */
-#if defined __need_off_t || defined __need___off64_t
- /* ...to identify a requirement for selective inclusion of one or more
-  * of these type definitions from "sys/types.h"; (note that we use the
-  * #include "..." form here, to ensure that we get the correct header
-  * file, relative to the location of this <stdio.h>).
+#else
+ /* ...or a 32-bit equivalent, for pre-MSVCRT.DLL users.
   */
-# include "sys/types.h"
+# define __need___off32_t
 #endif
 
+/* Note the use of the #include "..." form here, to ensure that we get
+ * the correct header file, relative to the location of this <stdio.h>
+ */
+#include "sys/types.h"
+
 #ifndef __VALIST
  /* Also similarly, for the va_list type, defined in "stdarg.h"
   */
@@ -298,10 +298,46 @@ _CRTIMP __cdecl __MINGW_NOTHROW  void   setbuf (FILE *, char *);
 /* Formatted Output
  *
  * MSVCRT implementations are not ANSI C99 conformant...
- * we offer these conforming alternatives from libmingwex.a
+ * we offer conforming alternatives from libmingwex.a
  */
 #undef  __mingw_stdio_redirect__
-#define __mingw_stdio_redirect__(F) __cdecl __MINGW_NOTHROW __mingw_##F
+#define __mingw_stdio_redirect__(F) __cdecl __MINGW_NOTHROW __Wformat(F)
+#define __Wformat_mingw_printf(F,A) __attribute__((__format__(__mingw_printf__,F,A)))
+
+#if __GNUC__ >= 6
+/* From GCC-6 onwards, we will provide customized -Wformat
+ * handling, via our own mingw_printf format category...
+ */
+#define __Wformat(F)           __Wformat_##F __mingw_##F
+
+#else  /* __GNUC__ < 6 */
+/* ...whereas, for earlier GCC, we preserve the status quo,
+ * offering no -Wformat checking for those functions which
+ * replace the MSVCRT.DLL versions...
+ */
+#define __Wformat(F)           __mingw_##F
+
+/* ...while degrading to gnu_printf checking for snprintf()
+ * and vsnprintf(), (which are ALWAYS MinGW.org variants).
+ */
+#define __mingw_printf__       __gnu_printf__
+#endif
+
+/* The following convenience macros specify the appropriate
+ * -Wformat checking for MSVCRT.DLL replacement functions...
+ */
+#define __Wformat_printf       __Wformat_mingw_printf(1,2)
+#define __Wformat_fprintf      __Wformat_mingw_printf(2,3)
+#define __Wformat_sprintf      __Wformat_mingw_printf(2,3)
+#define __Wformat_vprintf      __Wformat_mingw_printf(1,0)
+#define __Wformat_vfprintf     __Wformat_mingw_printf(2,0)
+#define __Wformat_vsprintf     __Wformat_mingw_printf(2,0)
+
+/* ...while this pair are specific to the two MinGW.org
+ * only functions.
+ */
+#define __Wformat_snprintf     __Wformat_mingw_printf(3,4)
+#define __Wformat_vsnprintf    __Wformat_mingw_printf(3,0)
 
 extern int __mingw_stdio_redirect__(fprintf)(FILE*, const char*, ...);
 extern int __mingw_stdio_redirect__(printf)(const char*, ...);
@@ -339,7 +375,7 @@ extern int __mingw_stdio_redirect__(vsnprintf)(char*, size_t, const char*, __VAL
  */
 extern unsigned int _mingw_output_format_control( unsigned int, unsigned int );
 
-#if __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO || defined _ISOC99_SOURCE
 /* User has expressed a preference for C99 conformance...
  */
 # undef __mingw_stdio_redirect__
@@ -357,12 +393,20 @@ extern unsigned int _mingw_output_format_control( unsigned int, unsigned int );
  */
 #  define __mingw_stdio_redirect__  static __inline__ __cdecl __MINGW_NOTHROW
 
-# else
+# else /* Neither C++ nor __GNUC__ */
 /* Can't use inlines; fall back on module local static stubs.
  */
 #  define __mingw_stdio_redirect__  static __cdecl __MINGW_NOTHROW
-# endif
 
+# endif        /* Neither C++ nor __GNUC__ */
+#endif /* __USE_MINGW_ANSI_STDIO || defined _ISOC99_SOURCE */
+
+#if __USE_MINGW_ANSI_STDIO
+/* The MinGW ISO-C conforming implementations of the printf() family
+ * of functions are to be used, in place of non-conforming Microsoft
+ * implementations; force call redirection, via the following set of
+ * in-line functions.
+ */
 __mingw_stdio_redirect__
 int fprintf (FILE *__stream, const char *__format, ...)
 {
@@ -411,7 +455,7 @@ int vsprintf (char *__stream, const char *__format, __VALIST __local_argv)
   return __mingw_vsprintf( __stream, __format, __local_argv );
 }
 
-#else
+#else  /* !__USE_MINGW_ANSI_STDIO */
 /* Default configuration: simply direct all calls to MSVCRT...
  */
 _CRTIMP __cdecl __MINGW_NOTHROW  int fprintf (FILE *, const char *, ...);
@@ -421,12 +465,50 @@ _CRTIMP __cdecl __MINGW_NOTHROW  int vfprintf (FILE *, const char *, __VALIST);
 _CRTIMP __cdecl __MINGW_NOTHROW  int vprintf (const char *, __VALIST);
 _CRTIMP __cdecl __MINGW_NOTHROW  int vsprintf (char *, const char *, __VALIST);
 
-#endif
+#endif /* !__USE_MINGW_ANSI_STDIO */
+
+#if __GNUC__ && defined _ISOC99_SOURCE
+/* Although MinGW implementations of the ISO-C99 snprintf() and
+ * vsnprintf() functions do not conflict with any implementation
+ * in MSVCRT.DLL, (because MSVCRT.DLL does not implement either),
+ * there are -Wformat attribute conflicts with the GCC built-in
+ * prototypes associated with each; by providing the following
+ * in-line function implementations, which will override GCC's
+ * built-in prototypes, we may avoid these conflicts.
+ */
+__mingw_stdio_redirect__
+int snprintf (char *__buf, size_t __len, const char *__format, ...)
+{
+  register int __retval;
+  __builtin_va_list __local_argv; __builtin_va_start( __local_argv, __format );
+  __retval = __mingw_vsnprintf( __buf, __len, __format, __local_argv );
+  __builtin_va_end( __local_argv );
+  return __retval;
+}
+
+__mingw_stdio_redirect__
+int vsnprintf (char *__buf, size_t __len, const char *__format, __VALIST __local_argv)
+{
+  return __mingw_vsnprintf( __buf, __len, __format, __local_argv );
+}
+#endif /* __GNUC__ && defined _ISOC99_SOURCE */
+
 /* Regardless of user preference, always offer these alternative
- * entry points, for direct access to the MSVCRT implementations.
+ * entry points, for direct access to the MSVCRT implementations,
+ * with ms_printf -Wformat checking in each case.
  */
+#undef  __Wformat
 #undef  __mingw_stdio_redirect__
-#define __mingw_stdio_redirect__(F) __cdecl __MINGW_NOTHROW __msvcrt_##F
+#define __mingw_stdio_redirect__(F) __cdecl __MINGW_NOTHROW __Wformat(F)
+#define __Wformat_msvcrt_printf(F,A) __attribute__((__format__(__ms_printf__,F,A)))
+#define __Wformat(F) __Wformat_ms_##F __msvcrt_##F
+
+#define __Wformat_ms_printf    __Wformat_msvcrt_printf(1,2)
+#define __Wformat_ms_fprintf   __Wformat_msvcrt_printf(2,3)
+#define __Wformat_ms_sprintf   __Wformat_msvcrt_printf(2,3)
+#define __Wformat_ms_vprintf   __Wformat_msvcrt_printf(1,0)
+#define __Wformat_ms_vfprintf  __Wformat_msvcrt_printf(2,0)
+#define __Wformat_ms_vsprintf  __Wformat_msvcrt_printf(2,0)
 
 _CRTIMP int __mingw_stdio_redirect__(fprintf)(FILE *, const char *, ...);
 _CRTIMP int __mingw_stdio_redirect__(printf)(const char *, ...);
@@ -436,6 +518,7 @@ _CRTIMP int __mingw_stdio_redirect__(vprintf)(const char *, __VALIST);
 _CRTIMP int __mingw_stdio_redirect__(vsprintf)(char *, const char *, __VALIST);
 
 #undef  __mingw_stdio_redirect__
+#undef  __Wformat
 
 /* The following three ALWAYS refer to the MSVCRT implementations...
  */
@@ -450,10 +533,14 @@ _CRTIMP __cdecl __MINGW_NOTHROW  int _vscprintf (const char *, __VALIST);
  * NOT compatible with C99, but the following are; if you want the
  * MSVCRT behaviour, you MUST use the Microsoft "uglified" names.
  */
-__cdecl __MINGW_NOTHROW  int snprintf (char *, size_t, const char *, ...);
-__cdecl __MINGW_NOTHROW  int vsnprintf (char *, size_t, const char *, __VALIST);
+__cdecl __MINGW_NOTHROW __Wformat_snprintf
+int snprintf (char *, size_t, const char *, ...);
 
-__cdecl __MINGW_NOTHROW  int vscanf (const char * __restrict__, __VALIST);
+__cdecl __MINGW_NOTHROW __Wformat_vsnprintf
+int vsnprintf (char *, size_t, const char *, __VALIST);
+
+__cdecl __MINGW_NOTHROW
+int vscanf (const char * __restrict__, __VALIST);
 
 __cdecl __MINGW_NOTHROW
 int vfscanf (FILE * __restrict__, const char * __restrict__, __VALIST);
@@ -465,8 +552,7 @@ int vsscanf (const char * __restrict__, const char * __restrict__, __VALIST);
 #endif /* <stdio.h> included in its own right */
 
 #if __MSVCRT_VERSION__ >= __MSVCR80_DLL || _WIN32_WINNT >= _WIN32_WINNT_VISTA
-/*
- * In MSVCR80.DLL, (and its descendants), Microsoft introduced variants
+/* In MSVCR80.DLL, (and its descendants), Microsoft introduced variants
  * of the printf() functions, with names qualified by an underscore prefix
  * and "_p" or "_p_l" suffixes; implemented in Microsoft's typically crass,
  * non-standard, and non-portable fashion, these provide support for access
@@ -541,8 +627,7 @@ int _vsprintf_p_l (char *, size_t, const char *, locale_t, __VALIST);
 
 #if ! (defined _STDIO_H && defined _WCHAR_H)
 #if __MSVCRT_VERSION__ >= __MSVCR80_DLL || _WIN32_WINNT >= _WIN32_WINNT_VISTA
-/*
- * Wide character variants of the foregoing "positional parameter" printf()
+/* Wide character variants of the foregoing "positional parameter" printf()
  * functions; MSDN says that these should be declared when either <stdio.h>, or
  * <wchar.h> is included, so we make them selectively available to <wchar.h>,
  * but, just as in the foregoing, we advise against their use.
@@ -688,9 +773,61 @@ _CRTIMP __cdecl __MINGW_NOTHROW  int    fseek (FILE *, long, int);
 _CRTIMP __cdecl __MINGW_NOTHROW  long   ftell (FILE *);
 _CRTIMP __cdecl __MINGW_NOTHROW  void   rewind (FILE *);
 
+#ifdef __USE_MINGW_FSEEK
+/* Workaround for a limitation on Win9x where a file is not zero padded
+ * on write, following a seek beyond the original end of file; supporting
+ * redirector functions are implemented in libmingwex.a
+ *
+ * Note: this is improper usage.  __USE_MINGW_FSEEK exhibits the form of a
+ * private (system reserved) feature test macro; as such, users should not
+ * define it directly, and thus, it really should not have been defined at
+ * this point; discourage this practice.
+ */
+#warning "The __USE_MINGW_FSEEK feature test is deprecated"
+#pragma info "Define _WIN32_WINDOWS, instead of __USE_MINGW_FSEEK"
+
+#elif _WIN32_WINDOWS >= _WIN32_WINDOWS_95 && _WIN32_WINDOWS < _WIN32_WINNT_WIN2K
+/* This is correct usage; the private __USE_MINGW_FSEEK feature affects only
+ * Win9x, so enable it implicitly when the _WIN32_WINDOWS feature is specified,
+ * thus indicating the user's intent to target a Win9x platform.
+ */
+#define __USE_MINGW_FSEEK
+#endif
+
+#ifdef __USE_MINGW_FSEEK
+/* Regardless of how it may have become defined, when __USE_MINGW_FSEEK has
+ * been defined, we must redirect calls to fseek() and fwrite(), so that the
+ * Win9x zero padding limitation can be mitigated.
+ */
+__cdecl __MINGW_NOTHROW  int __mingw_fseek (FILE *, __off64_t, int);
+__CRT_ALIAS int fseek( FILE *__fp, long __offset, int __whence )
+{ return __mingw_fseek( __fp, (__off64_t)(__offset), __whence ); }
+
+__cdecl __MINGW_NOTHROW  size_t __mingw_fwrite (const void *, size_t, size_t, FILE *);
+__CRT_ALIAS size_t fwrite( const void *__buf, size_t __len, size_t __cnt, FILE *__fp )
+{ return __mingw_fwrite( __buf, __len, __cnt, __fp ); }
+#endif /* __USE_MINGW_FSEEK */
+
+/* An opaque data type used for storing file positions...  The contents
+ * of this type are unknown, but we (the compiler) need to know the size
+ * because the programmer using fgetpos and fsetpos will be setting aside
+ * storage for fpos_t aggregates.  Actually I tested using a byte array and
+ * it is fairly evident that fpos_t is a 32-bit type in CRTDLL.DLL, but in
+ * MSVCRT.DLL, it is a 64-bit type.  Define it in terms of an int type of
+ * the appropriate size, encapsulated within an aggregate type, to make
+ * it opaque to casting, and so discourage abuse.
+ */
+#ifdef __MSVCRT__
+typedef union { __int64 __value; __off64_t __offset; } fpos_t;
+#else
+typedef union { __int32 __value; __off32_t __offset; } fpos_t;
+#endif
+
+_CRTIMP __cdecl __MINGW_NOTHROW  int fgetpos (FILE *, fpos_t *);
+_CRTIMP __cdecl __MINGW_NOTHROW  int fsetpos (FILE *, const fpos_t *);
+
 #if _WIN32_WINNT >= _WIN32_WINNT_VISTA || __MSVCRT_VERSION__ >= __MSVCR80_DLL
- /*
-  * Microsoft introduced a number of variations on fseek() and ftell(),
+ /* Microsoft introduced a number of variations on fseek() and ftell(),
   * beginning with MSVCR80.DLL; the bare _fseeki64() and _ftelli64() were
   * subsequently integrated into MSVCRT.DLL, from Vista onward...
   */
@@ -698,8 +835,7 @@ _CRTIMP __cdecl __MINGW_NOTHROW  int    _fseeki64 (FILE *, __int64, int);
 _CRTIMP __cdecl __MINGW_NOTHROW __int64 _ftelli64 (FILE *);
 
 #if __MSVCRT_VERSION__ >= __MSVCR80_DLL
- /*
-  * ...while the "nolock" variants remain exclusive to MSVCR80.DLL, and
+ /* ...while the "nolock" variants remain exclusive to MSVCR80.DLL, and
   * its later MSVC specific derivatives.
   */
 _CRTIMP __cdecl __MINGW_NOTHROW  int    _fseek_nolock (FILE *, long, int);
@@ -709,36 +845,30 @@ _CRTIMP __cdecl __MINGW_NOTHROW  int    _fseeki64_nolock (FILE *, __int64, int);
 _CRTIMP __cdecl __MINGW_NOTHROW __int64 _ftelli64_nolock (FILE *);
 
 #endif  /* MSVCR80.DLL and later derivatives ONLY */
-#endif  /* MSVCR80.DLL and descendants, or MSVCRT.DLL since Vista */
-
-#ifdef __USE_MINGW_FSEEK
-/* Workaround for a limitation on Win9x where a file is not zero padded
- * on write, following a seek beyond the original end of file; these are
- * implemented in libmingwex.a
- */
-__cdecl __MINGW_NOTHROW  int    __mingw_fseek (FILE *, long, int);
-__cdecl __MINGW_NOTHROW  size_t __mingw_fwrite (const void *, size_t, size_t, FILE *);
-
-#define fwrite(buffer, size, count, fp)  __mingw_fwrite(buffer, size, count, fp)
-#define fseek(fp, offset, whence)        __mingw_fseek(fp, offset, whence)
-#endif /* __USE_MINGW_FSEEK */
 
-/* An opaque data type used for storing file positions... The contents of
- * this type are unknown, but we (the compiler) need to know the size
- * because the programmer using fgetpos and fsetpos will be setting aside
- * storage for fpos_t structres. Actually I tested using a byte array and
- * it is fairly evident that the fpos_t type is a long (in CRTDLL.DLL).
- * Perhaps an unsigned long? TODO? It's definitely a 64-bit number in
- * MSVCRT however, and for now `long long' will do.
- */
-#ifdef __MSVCRT__
-typedef long long  fpos_t;
-#else
-typedef long       fpos_t;
+#else  /* pre-MSVCR80.DLL or MSVCRT.DLL pre-Vista */
+/* The Microsoft DLLs don't provide either _fseeki64() or _ftelli64(), but
+ * they DO provide fgetpos(), fsetpos(), and _lseeki64(), which may be used
+ * to emulate the two missing functions.  (Note that we choose to provide
+ * these emulations in the form of MinGW external helper functions, rather
+ * than pollute the <stdio.h> namespace with declarations, such as that
+ * for _lseeki64(), which properly belongs in <io.h>).
+ */
+#ifndef __USE_MINGW_FSEEK
+/* If this option has been selected, an alternative emulation for _fseeki64()
+ * is provided later, to ensure that the call is wrapped in a MinGW specific
+ * fseek() handling API.
+ */
+int __cdecl __MINGW_NOTHROW __mingw_fseeki64 (FILE *, __int64, int);
+__CRT_ALIAS __cdecl __MINGW_NOTHROW  int _fseeki64 (FILE *__f, __int64 __o, int __w)
+{ return __mingw_fseeki64 (__f, __o, __w); }
 #endif
 
-_CRTIMP __cdecl __MINGW_NOTHROW  int fgetpos (FILE *, fpos_t *);
-_CRTIMP __cdecl __MINGW_NOTHROW  int fsetpos (FILE *, const fpos_t *);
+__int64 __cdecl __MINGW_NOTHROW __mingw_ftelli64 (FILE *);
+__CRT_ALIAS __cdecl  __int64 __MINGW_NOTHROW _ftelli64 (FILE *__file )
+{ return __mingw_ftelli64 (__file); }
+
+#endif /* pre-MSVCR80.DLL or MSVCRT.DLL pre-Vista */
 
 /* Error Functions
  */
@@ -756,7 +886,6 @@ inline __cdecl __MINGW_NOTHROW  int ferror (FILE * __F){ return __F->_flag & _IO
 _CRTIMP __cdecl __MINGW_NOTHROW  void clearerr (FILE *);
 _CRTIMP __cdecl __MINGW_NOTHROW  void perror (const char *);
 
-
 #ifndef __STRICT_ANSI__
 /*
  * Pipes
@@ -883,14 +1012,20 @@ FILE * __cdecl __MINGW_NOTHROW  fopen64 (const char * filename, const char * mod
 int __cdecl __MINGW_NOTHROW  fseeko64 (FILE *, __off64_t, int);
 
 #ifdef __USE_MINGW_FSEEK
-int __cdecl __MINGW_NOTHROW __mingw_fseeko64 (FILE *, __off64_t, int);
-#define fseeko64(fp, offset, whence)  __mingw_fseeko64(fp, offset, whence)
+/* When this option is selected, we need to redirect calls to _fseeki64()
+ * and fseeko64() through a MinGW specific wrapper.  Since the two functions
+ * are fundamentally identical, differing only in the type of the "offset"
+ * argument, (and both types are effectively 64-bit signed ints anyway),
+ * the same wrapper will suffice for both.
+ */
+__CRT_ALIAS int _fseeki64( FILE *__fp, __int64 __offset, int __whence )
+{ return __mingw_fseek( __fp, (__off64_t)(__offset), __whence ); }
+
+__CRT_ALIAS int fseeko64( FILE *__fp, __off64_t __offset, int __whence )
+{ return __mingw_fseek( __fp, __offset, __whence ); }
 #endif
 
-__CRT_ALIAS __off64_t __cdecl __MINGW_NOTHROW ftello64 (FILE *);
-__CRT_ALIAS __LIBIMPL__(( FUNCTION = ftello64 ))
-__off64_t __cdecl __MINGW_NOTHROW ftello64 (FILE * stream)
-{ fpos_t __pos; return (fgetpos(stream, &__pos)) ? -1LL : (__off64_t)(__pos); }
+__off64_t __cdecl __MINGW_NOTHROW ftello64 (FILE *);
 
 #endif /* __MSVCRT__ && !__NO_MINGW_LFS */
 #endif /* !__STRICT_ANSI__ */
@@ -950,12 +1085,13 @@ _CRTIMP __cdecl __MINGW_NOTHROW  FILE    * _wpopen (const wchar_t *, const wchar
 #endif /* __MSVCRT__ */
 
 #ifdef _ISOC99_SOURCE
+__JMPSTUB__(( FUNCTION = snwprintf, DLLENTRY = _snwprintf ))
 __cdecl __MINGW_NOTHROW  int snwprintf (wchar_t *, size_t, const wchar_t *, ...);
 __cdecl __MINGW_NOTHROW  int vsnwprintf (wchar_t *, size_t, const wchar_t *, __VALIST);
 
 #ifndef __NO_INLINE__
 __CRT_INLINE __cdecl __MINGW_NOTHROW
-__JMPSTUB__(( FUNCTION = vsnwprintf, REMAPPED = _vsnwprintf ))
+__JMPSTUB__(( FUNCTION = vsnwprintf, DLLENTRY = _vsnwprintf ))
 int vsnwprintf (wchar_t *__s, size_t __n, const wchar_t *__fmt, __VALIST __arg)
 { return _vsnwprintf ( __s, __n, __fmt, __arg); }
 #endif