OSDN Git Service

Reimplement wcstof(), and wcstold() functions.
authorKeith Marshall <keith@users.osdn.me>
Wed, 4 Mar 2020 19:20:34 +0000 (19:20 +0000)
committerKeith Marshall <keith@users.osdn.me>
Wed, 4 Mar 2020 19:20:34 +0000 (19:20 +0000)
mingwrt/ChangeLog
mingwrt/Makefile.in
mingwrt/include/stdlib.h
mingwrt/mingwex/mb_wc_common.h [deleted file]
mingwrt/mingwex/wcstof.c [deleted file]
mingwrt/mingwex/wcstofp.c [new file with mode: 0644]
mingwrt/mingwex/wcstold.c [deleted file]

index b06bc3f..79737b8 100644 (file)
@@ -1,3 +1,24 @@
+2020-03-04  Keith Marshall  <keith@users.osdn.me>
+
+       Reimplement wcstof(), and wcstold() functions.
+
+       * mingwex/wcstofp.c: New file; it implements...
+       (wcstof, wcstold): ...these functions; each is an alias for...
+       (__mingw_wcstof, __mingw_wcstold): ...these, respectively; also...
+       (__mingw_wcstod): ...this; all are implemented in terms of...
+       (__mingw_wcstofp_prescan, __mingw_wcstofp_prepare)
+       (__mingw_wcstofp_bufsize): ...these; implement them.
+
+       * Makefile.in (libmingwex.a): Add dependency references...
+       (wcstofp.$OBJEXT, wcstod.$OBJEXT): ...for these; also include with...
+       (wcstof.$OBJEXT, wcstold.$OBJEXT): ...these, in new build rule.
+
+       * include/stdlib.h (__mingw_wcstod, __mingw_wcstof)
+       (__mingw_wcstold): Declare them.
+
+       * mingwex/mb_wc_common.h mingwex/wcstof.c mingwex/wcstold.c: Files
+       are obsolete, and no longer required; delete them.
+
 2020-03-03  Keith Marshall  <keith@users.osdn.me>
 
        Reimplement btowc(), and wctob() functions.
index 1bcf3a0..fb25113 100644 (file)
@@ -468,9 +468,11 @@ libmingwex.a: $(addsuffix .$(OBJEXT), mkstemp mkdtemp cryptnam setenv)
 
 vpath %.s ${mingwrt_srcdir}/mingwex
 vpath %.sx ${mingwrt_srcdir}/mingwex
-libmingwex.a: $(addsuffix .$(OBJEXT), codeset fwide mbrconv mbrscan mbrlen \
-  mbrtowc mbsrtowcs mbsinit strnlen wcharmap wcrtomb wcsrtombs wcsnlen wcstof \
-  wcstold wctob wctrans wctype wmemchr wmemcmp wmemcpy wmemmove wmemset)
+libmingwex.a: $(addsuffix .$(OBJEXT), codeset fwide mbrconv mbrscan mbrlen)
+libmingwex.a: $(addsuffix .$(OBJEXT), mbrtowc mbsrtowcs mbsinit strnlen wcharmap)
+libmingwex.a: $(addsuffix .$(OBJEXT), wcrtomb wcsrtombs wcsnlen wcstod wcstof)
+libmingwex.a: $(addsuffix .$(OBJEXT), wcstofp wcstold wctob wctrans wctype)
+libmingwex.a: $(addsuffix .$(OBJEXT), wmemchr wmemcmp wmemcpy wmemmove wmemset)
 
 # The wcsnlen() function, enumerated above, is an adaptation of strnlen();
 # we need a specific rule to compile it, from shared source.
@@ -478,6 +480,12 @@ libmingwex.a: $(addsuffix .$(OBJEXT), codeset fwide mbrconv mbrscan mbrlen \
 wcsnlen.$(OBJEXT): strnlen.sx
        $(COMPILE.sx) -D_UNICODE $^ -o $@
 
+# Similarly, the wcstod(), wcstof(), and wcstold() functions are
+# compiled from the common wcstofp.c source file.
+#
+$(addsuffix .$(OBJEXT), wcstod wcstof wcstold): %.$(OBJEXT): wcstofp.c
+       $(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) -D FUNCTION=$* -o $@ $<
+
 # For the math sources, we support the convention that a single
 # quux_generic.c source file will produce three objects: quux.o,
 # quuxf.o, and quuxl.o; since a change in the common source file
index 9eb4801..f39e909 100644 (file)
@@ -426,6 +426,20 @@ unsigned long wcstoul (const wchar_t *, wchar_t **, int);
 
 _CRTIMP __cdecl __MINGW_NOTHROW  double wcstod (const wchar_t *, wchar_t **);
 
+/* The following MinGW specific alternatives to wcstod(), which may
+ * offer more robust performance than the MSVCRT.DLL implementation,
+ * are provided in libmingwex.a; (the float and long double variants
+ * are simply aliases for the ISO-C99 equivalents which follow).
+ */
+__cdecl __MINGW_NOTHROW
+double __mingw_wcstod (const wchar_t *__restrict__, wchar_t **__restrict__);
+
+__cdecl __MINGW_NOTHROW
+float __mingw_wcstof (const wchar_t *__restrict__, wchar_t **__restrict__);
+
+__cdecl __MINGW_NOTHROW
+long double __mingw_wcstold (const wchar_t *__restrict__, wchar_t **__restrict__);
+
 #ifdef _ISOC99_SOURCE
 /* Variants on wcstod(), specified by ISO-C99; once again, MSVCRT.DLL
  * doesn't have them, but we offer them in libmingwex.a
diff --git a/mingwrt/mingwex/mb_wc_common.h b/mingwrt/mingwex/mb_wc_common.h
deleted file mode 100644 (file)
index d1c2f9d..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <locale.h>
-#include <string.h>
-#include <stdlib.h>
-
-static inline
-unsigned int get_codepage (void)
-{
-  /* locale :: "lang[_country[.code_page]]" | ".code_page"  */
-  char * cp_string;
-  if ((cp_string = strchr (setlocale(LC_CTYPE, NULL), '.')))
-    return  ((unsigned) atoi (cp_string + 1));
-  return 0;
-}
diff --git a/mingwrt/mingwex/wcstof.c b/mingwrt/mingwex/wcstof.c
deleted file mode 100644 (file)
index 66e1a30..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*  Wide char wrapper for strtof
- *  Revision history:
- *  25 Aug 2006 Initial version.
- *
- *  Contributor:   Danny Smith <dannysmith@users.sourceforege.net>
- */
-
- /* This routine has been placed in the public domain.*/
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <locale.h>
-#include <wchar.h>
-#include <stdlib.h>
-#include <string.h>
-#include <mbstring.h>
-
-#include "mb_wc_common.h"
-
-float wcstof (const wchar_t * __restrict__ wcs, wchar_t ** __restrict__ wcse)
-{
-  char * cs;
-  char * cse;
-  unsigned int i;
-  float ret;
-  const unsigned int cp = get_codepage ();
-
-  /* Allocate enough room for (possibly) mb chars */
-  cs = (char *) malloc ((wcslen(wcs)+1) * MB_CUR_MAX);
-
-  if (cp == 0) /* C locale */
-    {
-      for (i = 0; (wcs[i] != 0) && wcs[i] <= 255; i++)
-        cs[i] = (char) wcs[i];
-      cs[i]  = '\0';
-    }
-  else
-    {
-      int nbytes = -1;
-      int mb_len = 0;
-      /* loop through till we hit null or invalid character */
-      for (i = 0; (wcs[i] != 0) && (nbytes != 0); i++)
-       {
-         nbytes = WideCharToMultiByte(cp, WC_COMPOSITECHECK | WC_SEPCHARS,
-                                      wcs + i, 1, cs + mb_len, MB_CUR_MAX,
-                                      NULL, NULL);
-         mb_len += nbytes;
-       }
-      cs[mb_len] = '\0';
-    }
-
-  ret =  strtof (cs, &cse);
-
-  if (wcse)
-    {
-      /* Make sure temp mbstring cs has 0 at cse.  */
-      *cse = '\0';
-      i = _mbslen ((unsigned char*) cs); /* Number of chars, not bytes */
-      *wcse = (wchar_t *) wcs + i;
-    }
-  free (cs);
-
-  return ret;
-}
diff --git a/mingwrt/mingwex/wcstofp.c b/mingwrt/mingwex/wcstofp.c
new file mode 100644 (file)
index 0000000..aafa25b
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * wcstofp.c
+ *
+ * Implementation of ISO-C99 compatible wcstod(), wcstold(), and wcstof()
+ * functions, placed into the "__mingw_" pseudo-namespace, with enhanced
+ * C99 compatibility, and codeset coverage.
+ *
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keith@users.osdn.me>
+ * Copyright (C) 2020, 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.
+ *
+ *
+ * Compile with "-D FUNCTION=wcstod -o wcstod.o", or equivalent for each
+ * of wcstold() and wcstof(), to create free-standing object modules for
+ * each supported function; additionally, compile without "-D FUNCTION",
+ * and with "-o wcstofp.o", (or with "-D FUNCTION=wcstofp -o wcstofp.o"),
+ * to create the mandatory common supporting object code module.
+ *
+ */
+#define _ISOC99_SOURCE
+
+/* Parsing of floating point values, from wchar_t strings, is performed
+ * after conversion to the MBCS domain; to support any codeset with more
+ * than two bytes per code point, we require MinGW.org's extended codeset
+ * mapping API.
+ */
+#include "wcharmap.h"
+
+/* Declare prototypes, visible within each derived compilation unit, for
+ * each supporting function which is to be compiled into the common unit.
+ */
+const wchar_t *__mingw_wcstofp_prescan( const wchar_t * );
+size_t __mingw_wcstofp_prepare( const wchar_t *, char *, size_t );
+size_t __mingw_wcstofp_bufsize( const wchar_t * );
+
+/* Ensure that the function to be compiled has been specified...
+ */
+#ifndef FUNCTION
+/* ...or alternatively, fall back to compilation of the common "wcstofp"
+ * support code module...
+ */
+#define FUNCTION               wcstofp
+#endif
+/* ...and define a symbolic selector for the latter.
+ */
+#define wcstofp                1
+
+#if FUNCTION
+/* Default FUNCTION assignment -- compile the core support routines,
+ * common to all public API entry points.
+ */
+const wchar_t *__mingw_wcstofp_prescan( const wchar_t *nptr )
+{
+  /* Helper function to locate the effective starting point of a wchar_t
+   * string, ignoring any leading white-space.
+   */
+  if( nptr == NULL ) errno = EINVAL;
+  else while( iswspace( *nptr ) ) ++nptr;
+  return nptr;
+}
+
+size_t __mingw_wcstofp_prepare ( const wchar_t *nptr, char *mbs, size_t max )
+{
+  /* Helper function to prepare for interpretation of a wchar_t string
+   * representation of a floating point number; determines the size of
+   * buffer required, and optionally converts to MBCS representation,
+   * for interpretation by an apropriate string to binary converter.
+   */
+  size_t nbytes = (size_t)(0);
+  while( *nptr != L'\0' )
+  { /* Excluding the terminating NUL, convert wchar_t string elements
+     * one by one...
+     */
+    size_t count = __mingw_wctomb_convert( mbs, max, nptr++, 1 );
+
+    /* ...and, for each successfully converted, without exceeding the
+     * specified maximum conversion buffer length...
+     */
+    if( count != (size_t)(-1) )
+    { /* ...optionally store its MBCS equivalent, while unconditionally
+       * the actual buffer length requirement...
+       */
+      if( mbs != NULL ) { mbs += count; max -= count; }
+      nbytes += count;
+    }
+    /* Bail out early, if any element cannot be converted successfully,
+     * returning the count of MBCS bytes up to point of failure...
+     */
+    else return nbytes;
+  }
+  /* ...or similarly, the count of MBCS bytes for complete conversion,
+   * when the entire wchar_t string can be successfully converted.
+   */
+  return nbytes;
+}
+
+/* A wrapper around the preceding function, to determine the required
+ * buffer size, without storing the MBCS conversion; used by callers,
+ * to allocate buffers of suitable size.
+ */
+size_t __mingw_wcstofp_bufsize( const wchar_t *nptr )
+{ return 1 + __mingw_wcstofp_prepare( nptr, NULL, 0 ); }
+
+#else
+/* Compile function code for one specific public API entry point.
+ */
+#undef wcstod
+#undef wcstold
+#undef wcstof
+
+/* Define macros to specify the one specific entry point name...
+ */
+#define __mingw_redirect(FUNCTION)     set(__mingw,FUNCTION)
+
+/* ...and the associated data type, initial value, and corresponding
+ * MBCS string to binary conversion function name.
+ */
+#define set(FUNCTION,NAME)             FUNCTION##_##NAME
+#define datatype(FUNCTION)             set(FUNCTION,datatype)
+#define initval(FUNCTION)              set(FUNCTION,initval)
+#define strtofp(FUNCTION)              set(FUNCTION,strtofp)
+
+/* Specify MBCS converter, data type, and initial value for the
+ * __mingw_wcstod() function.
+ */
+#define wcstod_strtofp                 strtod
+#define wcstod_datatype                double
+#define wcstod_initval                 0.0
+
+/* Likewise, for the __mingw_wcstold() function...
+ */
+#define wcstold_strtofp                strtold
+#define wcstold_datatype               long double
+#define wcstold_initval                0.0L
+
+/* ...and the __mingw_wcstof() function.
+ */
+#define wcstof_strtofp                 strtof
+#define wcstof_datatype                float
+#define wcstof_initval                 0.0F
+
+/* Generic API function implementation, in terms of the above.
+ */
+datatype(FUNCTION) __mingw_redirect(FUNCTION)
+( const wchar_t *restrict nptr, wchar_t **restrict endptr )
+{
+  /* Initialize, to return appropriately typed zero, in the event
+   * of no valid floating point representation being found.
+   */
+  datatype(FUNCTION) retval = initval(FUNCTION);
+
+  /* Advance the wchar_t string pointer, beyond any white-space
+   * characters which may be present.
+   */
+  if( (nptr = __mingw_wcstofp_prescan( nptr )) != NULL )
+  {
+    /* We found a candidate wchar_t string for interpretation;
+     * allocate buffer space, for conversion to an MBCS string,
+     * with respect to the codeset for the current locale.
+     */
+    size_t buflen;
+    (void)(__mingw_wctomb_codeset_init());
+    if( (buflen = __mingw_wcstofp_bufsize( nptr )) > 0 )
+    { char mbstr[buflen], *endmark;
+
+      /* Convert to MBCS, appending NUL terminator, and attempt
+       * equivalent binary floating point interpretation.
+       */
+      mbstr[__mingw_wcstofp_prepare( nptr, mbstr, buflen )] = '\0';
+      retval = strtofp(FUNCTION)( mbstr, &endmark );
+
+      if( endptr != NULL )
+      { /* Caller wants to check for any junk, following the
+        * numeric representation within the original wchar_t
+        * string, but we know only the corresponding offset
+        * of trailing junk within the MBCS string; step along
+        * the wchar_t string, converting one element at a time,
+        * until the aggregate conversion length matches the
+        * known MBCS junk offset.
+        */
+       char *p = mbstr;
+       while( p < endmark )
+         p += __mingw_wctomb_convert( NULL, 0, nptr++, 1 );
+       *endptr = (wchar_t *)(nptr);
+      }
+    }
+  }
+  /* Return the floating point result, whether it was interpreted
+   * from the given wchar_t string, or remains as initial default.
+   */
+  return retval;
+}
+
+/* Microsoft's runtime library provides its own implementation for
+ * wcstod(), but (prior to non-free MSVCR120.DLL) not for wcstof(),
+ * or wcstold(); request creation of aliases for the latter pair...
+ */
+#define wcstof                 1
+#define wcstold                1
+
+#if FUNCTION
+/* ...then implement macros...
+ */
+#define stringify(NAME)        #NAME
+#define mkstring(NAME)         stringify(NAME)
+
+/* ...avoiding substitution of the function names...
+ */
+#undef wcstof
+#undef wcstold
+
+/* ...to actually implement these aliases.
+ */
+datatype(FUNCTION)
+__attribute__((__weak__,__alias__(mkstring(__mingw_redirect(FUNCTION)))))
+FUNCTION ( const wchar_t *restrict nptr, wchar_t **restrict endptr );
+
+#endif
+#endif
+
+/* $RCSfile$: end of file */
diff --git a/mingwrt/mingwex/wcstold.c b/mingwrt/mingwex/wcstold.c
deleted file mode 100644 (file)
index 9198303..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*  Wide char wrapper for strtold
- *  Revision history:
- *  6 Nov 2002 Initial version.
- *  25 Aug 2006  Don't use strtold internal functions.
- *
- *  Contributor:   Danny Smith <dannysmith@users.sourceforege.net>
- */
-
- /* This routine has been placed in the public domain.*/
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <locale.h>
-#include <wchar.h>
-#include <stdlib.h>
-#include <string.h>
-#include <mbstring.h>
-
-#include "mb_wc_common.h"
-
-long double wcstold (const wchar_t * __restrict__ wcs, wchar_t ** __restrict__ wcse)
-{
-  char * cs;
-  char * cse;
-  unsigned int i;
-  long double ret;
-  const unsigned int cp = get_codepage ();
-
-  /* Allocate enough room for (possibly) mb chars */
-  cs = (char *) malloc ((wcslen(wcs)+1) * MB_CUR_MAX);
-
-  if (cp == 0) /* C locale */
-    {
-      for (i = 0; (wcs[i] != 0) && wcs[i] <= 255; i++)
-        cs[i] = (char) wcs[i];
-      cs[i]  = '\0';
-    }
-  else
-    {
-      int nbytes = -1;
-      int mb_len = 0;
-      /* loop through till we hit null or invalid character */
-      for (i = 0; (wcs[i] != 0) && (nbytes != 0); i++)
-       {
-         nbytes = WideCharToMultiByte(cp, WC_COMPOSITECHECK | WC_SEPCHARS,
-                                      wcs + i, 1, cs + mb_len, MB_CUR_MAX,
-                                      NULL, NULL);
-         mb_len += nbytes;
-       }
-      cs[mb_len] = '\0';
-    }
-
-  ret =  strtold (cs, &cse);
-
-  if (wcse)
-    {
-      /* Make sure temp mbstring has 0 at cse.  */
-      *cse = '\0';
-      i = _mbslen ((unsigned char*) cs); /* Number of chars, not bytes */
-      *wcse = (wchar_t *) wcs + i;
-    }
-  free (cs);
-
-  return ret;
-}