4 * Implementation of POSIX.1-2008 conforming strnlen(), and a wrapper
5 * extending it to conform with ISO-C11 TR-24731-1 strnlen_s().
9 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
10 * Copyright (C) 2016, MinGW.org Project
13 * Permission is hereby granted, free of charge, to any person obtaining a
14 * copy of this software and associated documentation files (the "Software"),
15 * to deal in the Software without restriction, including without limitation
16 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 * and/or sell copies of the Software, and to permit persons to whom the
18 * Software is furnished to do so, subject to the following conditions:
20 * The above copyright notice and this permission notice (including the next
21 * paragraph) shall be included in all copies or substantial portions of the
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 * DEALINGS IN THE SOFTWARE.
33 * This file implements a POSIX.1-2008 conforming strnlen() function, under
34 * the alternative public name of __mingw_strnlen(), (to avoid any possible
35 * conflict with Microsoft's DLL implementations, or a replacement function
36 * implemented by the user).
38 * Note that POSIX does not prescribe any error returns for its strnlen()
39 * function; in particular, it does not specify handling of a NULL pointer,
40 * passed as the string argument to count, and thus, a segmentation fault
41 * is a plausible outcome. This is consistent with the behaviour exhibited
42 * by Microsoft's implementation, and this implementation acts likewise.
44 * OTOH, ISO-C11 TR-24731-1 prescribes that strnlen_s() shall return zero,
45 * when passed a NULL pointer as the string argument; the alternative entry
46 * point, __mingw_strnlen_s(), checks for this anomaly, and acts accordingly,
47 * before continuing as for __mingw_strnlen(), when passed a valid pointer
48 * to a string argument; (this is consistent with the documented behaviour
49 * of Microsoft's strnlen_s() implementation).
51 * Note that I've chosen to implement this in assembly language to enable
52 * sharing of common code between two distinct entry points, with subtly
53 * differing behaviours, while avoiding the overhead of an extra function
54 * call to invoke such shared code; this also allows the code to exploit
55 * the CUP's string scanning instructions, (which GCC does not), and so
56 * achieves a more compact, (and likely more efficient), implementation.
61 .globl ___mingw_strnlen
62 .def ___mingw_strnlen; .scl 2; .type 32; .endef
65 /* Implements: size_t __mingw_strnlen (const char *string, size_t maxlen );
67 * Scans at most maxlen chars, returning the lesser of strlen (string) and
68 * maxlen; does NOT check for string == NULL, which may thus induce failure
69 * with a segmentation fault. Note that initialization of return count to
70 * zero, in EAX, also serves as the NUL char reference for SCASB, in AL.
72 pushl %edi /* must preserve this */
73 xorl %eax, %eax /* initialize return count to zero */
74 movl 8(%esp), %edx /* load address of string argument */
76 movl 12(%esp), %ecx /* load maxlen ... */
77 jecxz .L4 /* and jump to end, if it's zero */
79 cld /* scan string from low-->high address */
80 movl %edx, %edi /* using this as the scan pointer ... */
81 repne scasb /* as required by this CPU scan */
82 mov %edi, %eax /* note where we stopped ... */
83 jnz .L3 /* no NUL found; count is complete ... */
84 decl %eax /* NUL found and counted; discount it */
86 sub %edx, %eax /* compute effective count to return */
88 popl %edi /* restore saved register ... */
89 ret /* and we're done */
92 .globl ___mingw_strnlen_s
93 .def ___mingw_strnlen_s; .scl 2; .type 32; .endef
96 /* Implements: size_t __mingw_strnlen_s (const char *string, size_t maxlen );
98 * Exhibits identical behaviour to __mingw_strnlen(), EXCEPT that it DOES
99 * check for string == NULL, returning zero when found.
101 pushl %edi /* must preserve this */
102 xorl %eax, %eax /* initialize return count to zero */
103 movl 8(%esp), %edx /* load address of string argument ... */
104 testl %edx, %edx /* checking for NULL pointer, and ... */
105 jnz .L1 /* proceeding as strnlen(), if not ... */
106 popl %edi /* otherwise restore saved register ... */
107 ret /* and return zero count value */
109 /* $RCSfile$: end of file */