OSDN Git Service

Honour GLOB_CASEMATCH for globbing sets; cf. issue [#2327].
[mingw/mingw-org-wsl.git] / mingwrt / mingwex / strnlen.s
1 /*
2  * strnlen.s
3  *
4  * Implementation of POSIX.1-2008 conforming strnlen(), and a wrapper
5  * extending it to conform with ISO-C11 TR-24731-1 strnlen_s().
6  *
7  * $Id$
8  *
9  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
10  * Copyright (C) 2016, MinGW.org Project
11  *
12  *
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:
19  *
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
22  * Software.
23  *
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.
31  *
32  *
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).
37  *
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.
43  *
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).
50  *
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.
57  *
58  */
59 .text
60 .align  4
61 .globl  ___mingw_strnlen
62 .def    ___mingw_strnlen;       .scl    2;      .type   32;     .endef
63
64 ___mingw_strnlen:
65 /* Implements: size_t __mingw_strnlen (const char *string, size_t maxlen );
66  *
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.
71  */
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 */
75 .L1:
76         movl    12(%esp), %ecx  /* load maxlen ... */
77         jecxz   .L4             /* and jump to end, if it's zero */
78 .L2:
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 */
85 .L3:
86         sub     %edx, %eax      /* compute effective count to return */
87 .L4:
88         popl    %edi            /* restore saved register ... */
89         ret                     /* and we're done */
90
91 .align  4
92 .globl  ___mingw_strnlen_s
93 .def    ___mingw_strnlen_s;     .scl    2;      .type   32;     .endef
94
95 ___mingw_strnlen_s:
96 /* Implements: size_t __mingw_strnlen_s (const char *string, size_t maxlen );
97  *
98  * Exhibits identical behaviour to __mingw_strnlen(), EXCEPT that it DOES
99  * check for string == NULL, returning zero when found.
100  */
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 */
108
109 /* $RCSfile$: end of file */