OSDN Git Service

Implement wcsnlen() API per feature request [#2332].
authorKeith Marshall <keithmarshall@users.sourceforge.net>
Sat, 28 Jan 2017 16:20:51 +0000 (16:20 +0000)
committerKeith Marshall <keithmarshall@users.sourceforge.net>
Sat, 28 Jan 2017 16:20:51 +0000 (16:20 +0000)
--HG--
rename : mingwrt/mingwex/strnlen.s => mingwrt/mingwex/strnlen.sx

mingwrt/ChangeLog
mingwrt/Makefile.in
mingwrt/include/wchar.h
mingwrt/mingwex/strnlen.sx [moved from mingwrt/mingwex/strnlen.s with 74% similarity]

index 41a6e08..7bbe88c 100644 (file)
@@ -1,3 +1,28 @@
+2017-01-28  Keith Marshall  <keithmarshall@users.sourceforge.net>
+
+       Implement wcsnlen() API per feature request [#2332].
+
+       * mingwex/strnlen.s: Rename it as...
+       * mingwex/strnlen.sx: ...this; use C preprocessor logic to adapt...
+       (__mingw_strnlen): ...this existing function implementation for use...
+       [_UNICODE] (__mingw_wcsnlen): ...as this.
+
+       * include/wchar.h [_POSIX_C_SOURCE >= 200809L] (wcsnlen): Declare...
+       [__MSVCRT_VERSION__>=__MSVCR80_DLL]: ...using MS DLL implementation...
+       [!__MSVCRT_VERSION__>=__MSVCR80_DLL] (__mingw_wcsnlen): ...otherwise,
+       declare this, with inline __JMPSTUB__ implementation, providing...
+       (wcsnlen): ...this.
+
+       * Makefile.in (wcsnlen.$OBJEXT): New build rule.
+       (libmingwex.a): Add wcsnlen.$OBJEXT as new prerequisite.
+       (libmoldname.a, libmoldnamed.a): Add __JMPSTUB__ wrappers.
+       (libmoldname70.a, libmoldname70d.a): Likewise.
+       (libmoldname71.a, libmoldname71d.a): Likewise.
+
+       for all other MSVC non-free associated oldname import libraries.
+       (vpath): Add $srcdir/mingwex for %.sx; hence mapping for...
+       (jmpstub.sx): ...this becomes redundant; delete it.
+
 2017-01-26  Jason Hood  <jadoxa@yahoo.com.au>
 
        Honour GLOB_CASEMATCH for globbing sets; cf. issue [#2327].
index 0a3e5c3..6b7afca 100644 (file)
@@ -388,7 +388,7 @@ $(foreach name,coldname $(all_moldname),lib$(name).a): $(addsuffix .$(OBJEXT), \
 #
 $(foreach name,moldname $(addprefix moldname,70 71),lib$(name).a) \
 $(foreach name,moldname $(addprefix moldname,70 71),lib$(name)d.a): \
-  strnlen.jmpstub.$(OBJEXT)
+  strnlen.jmpstub.$(OBJEXT) wcsnlen.jmpstub.$(OBJEXT)
 
 coldname.def: %.def: ${mingwrt_srcdir}/moldname.def.in
        $(CC) -C -E -P -D__FILENAME__=$@ -D__CRTDLL__ -xc-header $< > $@
@@ -499,10 +499,16 @@ libmingwex.a: $(addsuffix .$(OBJEXT), getdelim gettimeofday)
 libmingwex.a: $(addsuffix .$(OBJEXT), dirent wdirent dlfcn)
 
 vpath %.s ${mingwrt_srcdir}/mingwex
+vpath %.sx ${mingwrt_srcdir}/mingwex
 libmingwex.a: $(addsuffix .$(OBJEXT), fwide mbrtowc mbsinit strnlen wcrtomb \
-  wcstof wcstold wctob wmemchr wmemcmp wmemcpy wmemmove wmemset)
+  wcsnlen wcstof wcstold wctob wctrans wctype wmemchr wmemcmp wmemcpy wmemmove \
+  wmemset)
 
-libmingwex.a: $(addsuffix .$(OBJEXT), wctrans wctype)
+# The wcsnlen() function, enumerated above, is an adaptation of strnlen();
+# we need a specific rule to compile it, from shared source.
+#
+wcsnlen.$(OBJEXT): strnlen.sx
+       $(COMPILE.sx) -D_UNICODE $^ -o $@
 
 # For the math sources, we support the convention that a single
 # quux_generic.c source file will produce three objects: quux.o,
@@ -553,7 +559,6 @@ libm_dummy.c: Makefile
 # entry points as stubs in libmingwex.a, via the following rules:
 #
 sinclude Makefile.stub
-vpath jmpstub.sx ${mingwrt_srcdir}/mingwex
 libstub_refnames = grep -lr '__$1.*FUNCTION *=' ${mingwrt_srcdir}
 jmpstub_prerequisites := $(shell $(call libstub_refnames,JMPSTUB)/include)
 libimpl_prerequisites := $(shell $(call libstub_refnames,LIBIMPL)/include)
index e4edd52..a10fb20 100644 (file)
@@ -467,6 +467,36 @@ _CRTIMP __cdecl __MINGW_NOTHROW  wchar_t *wcsupr (wchar_t *);
 #endif /* !_NO_OLDNAMES */
 #endif /* !__STRICT_ANSI__ */
 
+#if _POSIX_C_SOURCE >= 200809L
+#if __MSVCRT_VERSION__ >= __MSVCR80_DLL
+/* MSVCR80.DLL adds a (mostly) POSIX.1-2008 conforming wcsnlen(); (it's
+ * also available in MSVCRT.DLL from _WIN32_WINNT_VISTA onwards, but we
+ * pretend otherwise, since recent GCC will try to use the function when
+ * it can be found in libmsvcrt.a, so breaking it for use on WinXP and
+ * earlier).
+ */
+#ifndef __STRICT_ANSI__   /* N.B.: this is not an ISO-C function */
+_CRTIMP __cdecl __MINGW_NOTHROW  char *wcsnlen (const wchar_t *, size_t);
+#endif
+
+#else  /* MSVCRT.DLL || pre-MSVCR80.DLL */
+/* Emulation, to support recent POSIX.1; we prefer this for ALL versions
+ * of MSVCRT.DLL, (even those which already provide wcsnlen()); to avoid
+ * the GCC breakage noted above.  (Note that we implement wcsnlen() with
+ * the alternative external name, __mingw_wcsnlen() in libmingwex.a, to
+ * avoid possible link time collision with MSVCR80.DLL's implementation,
+ * then map this to wcsnlen() via a __CRT_ALIAS, with stubs designated
+ * for linking from within the appropriate oldname libraries.
+ */
+extern size_t __mingw_wcsnlen (const wchar_t *, size_t);
+
+__JMPSTUB__(( LIB=coldname; FUNCTION=wcsnlen ))
+__CRT_ALIAS size_t wcsnlen (const wchar_t *__text, size_t __maxlen)
+{ return __mingw_wcsnlen (__text, __maxlen); }
+
+#endif /* MSVCRT.DLL || pre-MSVCR80.DLL */
+#endif /* _POSIX_C_SOURCE >= 200809L */
+
 /* This completes the set of declarations which are to be duplicated by
  * inclusion of <string.h>; revert the declarative condition, to make it
  * specific to <wchar.h> alone.
similarity index 74%
rename from mingwrt/mingwex/strnlen.s
rename to mingwrt/mingwex/strnlen.sx
index 66d7b49..463afb0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * strnlen.s
+ * strnlen.sx
  *
  * Implementation of POSIX.1-2008 conforming strnlen(), and a wrapper
  * extending it to conform with ISO-C11 TR-24731-1 strnlen_s().
@@ -7,7 +7,7 @@
  * $Id$
  *
  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
- * Copyright (C) 2016, MinGW.org Project
+ * Copyright (C) 2016, 2017, MinGW.org Project
  *
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * sharing of common code between two distinct entry points, with subtly
  * differing behaviours, while avoiding the overhead of an extra function
  * call to invoke such shared code; this also allows the code to exploit
- * the CUP's string scanning instructions, (which GCC does not), and so
+ * the CPU's string scanning instructions, (which GCC does not), and so
  * achieves a more compact, (and likely more efficient), implementation.
  *
  */
+#if defined UNICODE || defined _UNICODE
+/* The algorithm defined herein is effectively the same as that required
+ * as a substitute for wcsnlen()/wcsnlen_s(); map entry point names to the
+ * appropriate alternatives for scanning wchar_t *, (rather than char *),
+ * strings, (i.e. Microsoft's so-called UNICODE strings).
+ */
+# define ___mingw_strnlen    ___mingw_wcsnlen
+# define ___mingw_strnlen_s  ___mingw_wcsnlen_s
+
+/* The fundamental change required to scan whcar_t * strings, rather than
+ * char * strings, is that we must use the scasw instruction in place of
+ * the scasb instruction; map it accordingly.
+ */
+# define scasb  scasw
+#endif
+
 .text
 .align 4
 .globl ___mingw_strnlen
@@ -84,8 +100,22 @@ ___mingw_strnlen:
        decl    %eax            /* NUL found and counted; discount it */
 .L3:
        sub     %edx, %eax      /* compute effective count to return */
-.L4:
-       popl    %edi            /* restore saved register ... */
+
+#if defined UNICODE || defined _UNICODE
+/* By the time we get to here, the EAX register contains the effective
+ * length of the scanned string in bytes; this is the correct value to be
+ * returned, in the case of char * strings, but it is twice the correct
+ * length for wchar_t * strings, (possibly with one odd residual byte,
+ * left over from a partially discounted NUL wchar_t); we may adjust this,
+ * for the wchar_t * case, by a simple logical right shift, effectively
+ * dividing the even extent of the (unsigned) count by two, extracting
+ * the full wchar_t count, leaving any odd byte residual as remainder
+ * in the carry flag, where we may simply (and safely) ignore it.
+ */
+       shrl    %eax            /* convert byte count to wchar_t count */
+#endif
+
+.L4:   popl    %edi            /* restore saved register ... */
        ret                     /* and we're done */
 
 .align 4