281f6635e1503d4126f19f53e756f8ae0c8780ac
[platform/upstream/glibc.git] / sysdeps / i386 / i686 / strtok.S
1 /* strtok (str, delim) -- Return next DELIM separated token from STR.
2    For Intel 80686.
3    Copyright (C) 1998-2013 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
6
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, see
19    <http://www.gnu.org/licenses/>.  */
20
21 #include <sysdep.h>
22 #include "asm-syntax.h"
23 #include "bp-sym.h"
24 #include "bp-asm.h"
25
26 /* This file can be used for three variants of the strtok function:
27
28    strtok:
29         INPUT PARAMETER:
30         str             (sp + 4)
31         delim           (sp + 8)
32
33    strtok_r:
34         INPUT PARAMETER:
35         str             (sp + 4)
36         delim           (sp + 8)
37         save_ptr        (sp + 12)
38
39    We do a common implementation here.  */
40
41 #ifdef USE_AS_STRTOK_R
42 # define SAVE_PTR 0(%ecx)
43 #else
44         .bss
45         .local save_ptr
46         .type save_ptr, @object
47         .size save_ptr, 4
48 save_ptr:
49         .space 4
50
51 # ifdef PIC
52 #  define SAVE_PTR save_ptr@GOTOFF(%ebx)
53 # else
54 #  define SAVE_PTR save_ptr
55 # endif
56
57 # define FUNCTION strtok
58 #endif
59
60 #if !defined USE_AS_STRTOK_R && defined PIC
61 # define PARMS  LINKAGE+256+4   /* space for table and saved PIC register */
62 #else
63 # define PARMS  LINKAGE+256     /* space for table */
64 #endif
65 #define RTN     PARMS
66 #define STR     RTN+RTN_SIZE
67 #define DELIM   STR+PTR_SIZE
68 #ifdef USE_AS_STRTOK_R
69 # define SAVE   DELIM+PTR_SIZE
70 #endif
71
72         .text
73
74 #if !defined USE_AS_STRTOK_R && defined PIC
75 0:      movl (%esp), %ebx
76         ret
77 #endif
78
79 ENTRY (BP_SYM (FUNCTION))
80
81 #if !defined USE_AS_STRTOK_R && defined PIC
82         pushl %ebx                      /* Save PIC register.  */
83         cfi_adjust_cfa_offset (4)
84         cfi_rel_offset (ebx, 0)
85         call 0b
86         addl $_GLOBAL_OFFSET_TABLE_, %ebx
87 #endif
88
89         /* First we create a table with flags for all possible characters.
90            For the ASCII (7bit/8bit) or ISO-8859-X character sets which are
91            supported by the C string functions we have 256 characters.
92            Before inserting marks for the stop characters we clear the whole
93            table.  */
94         movl %edi, %edx
95         subl $256, %esp
96         cfi_adjust_cfa_offset (256)
97         movl $64, %ecx
98         movl %esp, %edi
99         xorl %eax, %eax
100         cld
101         rep
102         stosl
103
104         /* Note: %ecx = 0 !!! */
105         movl %edx, %edi
106
107         movl STR(%esp), %edx            /* Get start of string.  */
108
109 #ifdef USE_AS_STRTOK_R
110         /* The value is stored in the third argument.  */
111         movl SAVE(%esp), %eax
112         movl (%eax), %eax
113 #else
114         /* The value is in the local variable defined above.  But
115            we have to take care for PIC code.  */
116         movl SAVE_PTR, %eax
117 #endif
118
119         /* If the pointer is NULL we have to use the stored value of
120            the last run.  */
121         cmpl $0, %edx
122         cmove %eax, %edx
123         testl %edx, %edx
124         jz L(returnNULL)
125         movl DELIM(%esp), %eax          /* Get start of delimiter set.  */
126
127 /* For understanding the following code remember that %ecx == 0 now.
128    Although all the following instruction only modify %cl we always
129    have a correct zero-extended 32-bit value in %ecx.  */
130
131 L(2):   movb (%eax), %cl        /* get byte from stopset */
132         testb %cl, %cl          /* is NUL char? */
133         jz L(1)                 /* yes => start compare loop */
134         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
135
136         movb 1(%eax), %cl       /* get byte from stopset */
137         testb $0xff, %cl        /* is NUL char? */
138         jz L(1)                 /* yes => start compare loop */
139         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
140
141         movb 2(%eax), %cl       /* get byte from stopset */
142         testb $0xff, %cl        /* is NUL char? */
143         jz L(1)                 /* yes => start compare loop */
144         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
145
146         movb 3(%eax), %cl       /* get byte from stopset */
147         addl $4, %eax           /* increment stopset pointer */
148         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
149         testb $0xff, %cl        /* is NUL char? */
150         jnz L(2)                /* no => process next dword from stopset */
151
152 L(1):   leal -4(%edx), %eax     /* prepare loop */
153
154         /* We use a neat trick for the following loop.  Normally we would
155            have to test for two termination conditions
156            1. a character in the stopset was found
157            and
158            2. the end of the string was found
159            As a sign that the character is in the stopset we store its
160            value in the table.  The value of NUL is NUL so the loop
161            terminates for NUL in every case.  */
162
163 L(3):   addl $4, %eax           /* adjust pointer for full loop round */
164
165         movb (%eax), %cl        /* get byte from string */
166         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
167         jz L(4)                 /* no => start of token */
168
169         movb 1(%eax), %cl       /* get byte from string */
170         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
171         jz L(5)                 /* no => start of token */
172
173         movb 2(%eax), %cl       /* get byte from string */
174         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
175         jz L(6)                 /* no => start of token */
176
177         movb 3(%eax), %cl       /* get byte from string */
178         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
179         jnz L(3)                /* yes => start of loop */
180
181         incl %eax               /* adjust pointer */
182 L(6):   incl %eax
183 L(5):   incl %eax
184
185         /* Now we have to terminate the string.  */
186
187 L(4):   leal -4(%eax), %edx     /* We use %EDX for the next run.  */
188
189 L(7):   addl $4, %edx           /* adjust pointer for full loop round */
190
191         movb (%edx), %cl        /* get byte from string */
192         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
193         je L(8)                 /* yes => return */
194
195         movb 1(%edx), %cl       /* get byte from string */
196         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
197         je L(9)                 /* yes => return */
198
199         movb 2(%edx), %cl       /* get byte from string */
200         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
201         je L(10)                /* yes => return */
202
203         movb 3(%edx), %cl       /* get byte from string */
204         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
205         jne L(7)                /* no => start loop again */
206
207         incl %edx               /* adjust pointer */
208 L(10):  incl %edx
209 L(9):   incl %edx
210
211 L(8):   cmpl %eax, %edx
212         je L(returnNULL)        /* There was no token anymore.  */
213
214         movb $0, (%edx)         /* Terminate string.  */
215
216         /* Are we at end of string?  */
217         cmpb $0, %cl
218         leal 1(%edx), %ecx
219         cmovne %ecx, %edx
220
221         /* Store the pointer to the next character.  */
222 #ifdef USE_AS_STRTOK_R
223         movl SAVE(%esp), %ecx
224 #endif
225         movl %edx, SAVE_PTR
226
227 L(epilogue):
228         /* Remove the stopset table.  */
229         addl $256, %esp
230         cfi_adjust_cfa_offset (-256)
231 #if !defined USE_AS_STRTOK_R && defined PIC
232         popl %ebx
233         cfi_adjust_cfa_offset (-4)
234         cfi_restore (ebx)
235 #endif
236         RET_PTR
237
238 L(returnNULL):
239         xorl %eax, %eax
240 #ifdef USE_AS_STRTOK_R
241         movl SAVE(%esp), %ecx
242 #endif
243         movl %edx, SAVE_PTR
244         jmp L(epilogue)
245
246 END (BP_SYM (FUNCTION))