Thu May 30 11:24:05 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
[kopensolaris-gnu/glibc.git] / sysdeps / i386 / strtok.S
1 /* strtok (str, delim) -- Return next DELIM separated token from STR.
2 For Intel 80x86, x>=3.
3 Copyright (C) 1996 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
5 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
6
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 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 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public
18 License along with the GNU C Library; see the file COPYING.LIB.  If
19 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 #include <sysdep.h>
23
24 /* This file can be used for three variants of the strtok function:
25
26    strtok:
27         INPUT PARAMETER:
28         str             (sp + 4)
29         delim           (sp + 8)
30
31    strtok_r:
32         INPUT PARAMETER:
33         str             (sp + 4)
34         delim           (sp + 8)
35         save_ptr        (sp + 12)
36
37    We do a common implementation here.  */
38
39 #ifndef USE_AS_STRTOK_R
40         .bss
41         .local save_ptr
42         ASM_TYPE_DIRECTIVE (save_ptr, @object)
43         .size save_ptr, 4
44 save_ptr:
45         .space 4
46
47 #define FUNCTION strtok
48 #endif
49
50         .text
51
52 ENTRY (FUNCTION)
53
54         movl 4(%esp), %edx              /* Get start of string.  */
55         movl 8(%esp), %eax              /* Get start of delimiter set.  */
56
57 #if !defined (USE_AS_STRTOK_R) && defined (PIC)
58         pushl %ebx                      /* Save PIC register.  */
59         call Lhere
60 Lhere:  popl %ebx
61         addl $_GLOBAL_OFFSET_TABLE_+[.-Lhere], %ebx
62 #endif
63
64         /* If the pointer is NULL we have to use the stored value of
65            the last run.  */
66         cmpl $0, %edx
67         jne L0
68
69 #ifdef USE_AS_STRTOK_R
70         /* The value is stored in the third argument.  */
71         movl 12(%esp), %edx
72         movl (%edx), %edx
73 #else
74         /* The value is in the local variable defined above.  But
75            we have to take care for PIC code.  */
76 # ifndef PIC
77         movl save_ptr, %edx
78 # else
79         movl save_ptr@GOTOFF(%ebx), %edx
80 # endif
81 #endif
82
83 L0:
84         /* First we create a table with flags for all possible characters.
85            For the ASCII (7bit/8bit) or ISO-8859-X character sets which are
86            supported by the C string functions we have 256 characters.
87            Before inserting marks for the stop characters we clear the whole
88            table.  The unrolled form is much faster than a loop.  */
89         xorl %ecx, %ecx         /* %ecx = 0 !!! */
90
91         pushl %ecx              /* make a 256 bytes long block filled with 0 */
92         pushl %ecx
93         pushl %ecx
94         pushl %ecx
95         pushl %ecx
96         pushl %ecx
97         pushl %ecx
98         pushl %ecx
99         pushl %ecx
100         pushl %ecx
101         pushl %ecx
102         pushl %ecx
103         pushl %ecx
104         pushl %ecx
105         pushl %ecx
106         pushl %ecx
107         pushl %ecx
108         pushl %ecx
109         pushl %ecx
110         pushl %ecx
111         pushl %ecx
112         pushl %ecx
113         pushl %ecx
114         pushl %ecx
115         pushl %ecx
116         pushl %ecx
117         pushl %ecx
118         pushl %ecx
119         pushl %ecx
120         pushl %ecx
121         pushl %ecx
122         pushl %ecx
123         pushl %ecx
124         pushl %ecx
125         pushl %ecx
126         pushl %ecx
127         pushl %ecx
128         pushl %ecx
129         pushl %ecx
130         pushl %ecx
131         pushl %ecx
132         pushl %ecx
133         pushl %ecx
134         pushl %ecx
135         pushl %ecx
136         pushl %ecx
137         pushl %ecx
138         pushl %ecx
139         pushl %ecx
140         pushl %ecx
141         pushl %ecx
142         pushl %ecx
143         pushl %ecx
144         pushl %ecx
145         pushl %ecx
146         pushl %ecx
147         pushl %ecx
148         pushl %ecx
149         pushl $0                /* These immediate values make the label 2 */
150         pushl $0                /* to be aligned on a 16 byte boundary to */
151         pushl $0                /* get a better performance of the loop.  */
152         pushl $0
153         pushl $0
154         pushl $0
155
156 /* For understanding the following code remember that %ecx == 0 now.
157    Although all the following instruction only modify %cl we always
158    have a correct zero-extended 32-bit value in %ecx.  */
159
160 L2:     movb (%eax), %cl        /* get byte from stopset */
161         testb %cl, %cl          /* is NUL char? */
162         jz L1                   /* yes => start compare loop */
163         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
164
165         movb 1(%eax), %cl       /* get byte from stopset */
166         testb $0xff, %cl        /* is NUL char? */
167         jz L1                   /* yes => start compare loop */
168         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
169
170         movb 2(%eax), %cl       /* get byte from stopset */
171         testb $0xff, %cl        /* is NUL char? */
172         jz L1                   /* yes => start compare loop */
173         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
174
175         movb 3(%eax), %cl       /* get byte from stopset */
176         addl $4, %eax           /* increment stopset pointer */
177         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
178         testb $0xff, %cl        /* is NUL char? */
179         jnz L2                  /* no => process next dword from stopset */
180
181 L1:     leal -4(%edx), %eax     /* prepare loop */
182
183         /* We use a neat trick for the following loop.  Normally we would
184            have to test for two termination conditions
185            1. a character in the stopset was found
186            and
187            2. the end of the string was found
188            As a sign that the character is in the stopset we store its
189            value in the table.  The value of NUL is NUL so the loop
190            terminates for NUL in every case.  */
191
192 L3:     addl $4, %eax           /* adjust pointer for full loop round */
193
194         movb (%eax), %cl        /* get byte from string */
195         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
196         jz L4                   /* no => start of token */
197
198         movb 1(%eax), %cl       /* get byte from string */
199         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
200         jz L5                   /* no => start of token */
201
202         movb 2(%eax), %cl       /* get byte from string */
203         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
204         jz L6                   /* no => start of token */
205
206         movb 3(%eax), %cl       /* get byte from string */
207         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
208         jnz L3                  /* yes => start of loop */
209
210         incl %eax               /* adjust pointer */
211 L6:     incl %eax
212 L5:     incl %eax
213
214         /* Now we have to terminate the string.  */
215
216 L4:     leal -4(%eax), %edx     /* We use %EDX for the next run.  */
217
218 L7:     addl $4, %edx           /* adjust pointer for full loop round */
219
220         movb (%edx), %cl        /* get byte from string */
221         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
222         je L8                   /* yes => return */
223
224         movb 1(%edx), %cl       /* get byte from string */
225         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
226         je L9                   /* yes => return */
227
228         movb 2(%edx), %cl       /* get byte from string */
229         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
230         je L10                  /* yes => return */
231
232         movb 3(%edx), %cl       /* get byte from string */
233         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
234         jne L7                  /* no => start loop again */
235
236         incl %edx               /* adjust pointer */
237 L10:    incl %edx
238 L9:     incl %edx
239
240 L8:     /* Remove the stopset table.  */
241         addl $256, %esp
242
243         cmpl %eax, %edx
244         je LreturnNULL          /* There was no token anymore.  */
245
246         movb $0, (%edx)         /* Terminate string.  */
247
248         /* Are we at end of string?  */
249         cmpb $0, %cl
250         je L11
251
252         incl %edx
253 L11:
254
255         /* Store the pointer to the next character.  */
256 #ifdef USE_AS_STRTOK_R
257         movl 12(%esp), %ecx
258         movl %edx, (%ecx)
259 #else
260 # ifndef PIC
261         movl %edx, save_ptr
262 # else
263         movl %edx, save_ptr@GOTOFF(%ebx)
264         popl %ebx
265 # endif
266 #endif
267         ret
268
269 LreturnNULL:
270         xorl %eax, %eax
271
272         /* Store NULL as pointer to the next character.  */
273 #ifdef USE_AS_STRTOK_R
274         movl 12(%esp), %ecx
275         movl %eax, (%ecx)
276 #else
277 # ifndef PIC
278         movl %eax, save_ptr
279 # else
280         movl %eax, save_ptr@GOTOFF(%ebx)
281         popl %ebx
282 # endif
283 #endif
284         ret