Update copyright notices with scripts/update-copyrights.
[glibc.git] / sysdeps / i386 / i686 / strtok.S
blob794efbaed03ecacf76f338a0efa1561407594dde
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.
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.
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.
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/>.  */
21 #include <sysdep.h>
22 #include "asm-syntax.h"
23 #include "bp-sym.h"
24 #include "bp-asm.h"
26 /* This file can be used for three variants of the strtok function:
28    strtok:
29         INPUT PARAMETER:
30         str             (sp + 4)
31         delim           (sp + 8)
33    strtok_r:
34         INPUT PARAMETER:
35         str             (sp + 4)
36         delim           (sp + 8)
37         save_ptr        (sp + 12)
39    We do a common implementation here.  */
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 # if __BOUNDED_POINTERS__
50         .space 12
51 # else
52         .space 4
53 # endif
55 # ifdef PIC
56 #  define SAVE_PTR save_ptr@GOTOFF(%ebx)
57 # else
58 #  define SAVE_PTR save_ptr
59 # endif
61 # define FUNCTION strtok
62 #endif
64 #if !defined USE_AS_STRTOK_R && defined PIC
65 # define PARMS  LINKAGE+256+4   /* space for table and saved PIC register */
66 #else
67 # define PARMS  LINKAGE+256     /* space for table */
68 #endif
69 #define RTN     PARMS
70 #define STR     RTN+RTN_SIZE
71 #define DELIM   STR+PTR_SIZE
72 #ifdef USE_AS_STRTOK_R
73 # define SAVE   DELIM+PTR_SIZE
74 #endif
76         .text
78 #if !defined USE_AS_STRTOK_R && defined PIC
79 0:      movl (%esp), %ebx
80         ret
81 #endif
83 ENTRY (BP_SYM (FUNCTION))
84         ENTER
86 #if !defined USE_AS_STRTOK_R && defined PIC
87         pushl %ebx                      /* Save PIC register.  */
88         cfi_adjust_cfa_offset (4)
89         cfi_rel_offset (ebx, 0)
90         call 0b
91         addl $_GLOBAL_OFFSET_TABLE_, %ebx
92 #endif
94         /* First we create a table with flags for all possible characters.
95            For the ASCII (7bit/8bit) or ISO-8859-X character sets which are
96            supported by the C string functions we have 256 characters.
97            Before inserting marks for the stop characters we clear the whole
98            table.  */
99         movl %edi, %edx
100         subl $256, %esp
101         cfi_adjust_cfa_offset (256)
102         movl $64, %ecx
103         movl %esp, %edi
104         xorl %eax, %eax
105         cld
106         rep
107         stosl
109         /* Note: %ecx = 0 !!! */
110         movl %edx, %edi
112         movl STR(%esp), %edx            /* Get start of string.  */
114 #ifdef USE_AS_STRTOK_R
115         /* The value is stored in the third argument.  */
116         movl SAVE(%esp), %eax
117         movl (%eax), %eax
118 #else
119         /* The value is in the local variable defined above.  But
120            we have to take care for PIC code.  */
121         movl SAVE_PTR, %eax
122 #endif
124         /* If the pointer is NULL we have to use the stored value of
125            the last run.  */
126         cmpl $0, %edx
127         cmove %eax, %edx
128         testl %edx, %edx
129         jz L(returnNULL)
130 #if __BOUNDED_POINTERS__
131 # ifdef USE_AS_STRTOK_R
132         movl SAVE(%esp), %ecx   /* borrow %ecx for a moment */
133 # endif
134         je L(0)
135         /* Save bounds of incoming non-NULL STR into save area.  */
136         movl 4+STR(%esp), %eax
137         movl %eax, 4+SAVE_PTR
138         movl 8+STR(%esp), %eax
139         movl %eax, 8+SAVE_PTR
140 L(0):   CHECK_BOUNDS_LOW (%edx, SAVE_PTR)
141 # ifdef USE_AS_STRTOK_R
142         xorl %ecx, %ecx         /* restore %ecx to zero */
143 # endif
144 #endif
145         movl DELIM(%esp), %eax          /* Get start of delimiter set.  */
146         CHECK_BOUNDS_LOW (%eax, DELIM(%esp))
148 /* For understanding the following code remember that %ecx == 0 now.
149    Although all the following instruction only modify %cl we always
150    have a correct zero-extended 32-bit value in %ecx.  */
152 L(2):   movb (%eax), %cl        /* get byte from stopset */
153         testb %cl, %cl          /* is NUL char? */
154         jz L(1_1)               /* yes => start compare loop */
155         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
157         movb 1(%eax), %cl       /* get byte from stopset */
158         testb $0xff, %cl        /* is NUL char? */
159         jz L(1_2)               /* yes => start compare loop */
160         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
162         movb 2(%eax), %cl       /* get byte from stopset */
163         testb $0xff, %cl        /* is NUL char? */
164         jz L(1_3)               /* yes => start compare loop */
165         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
167         movb 3(%eax), %cl       /* get byte from stopset */
168         addl $4, %eax           /* increment stopset pointer */
169         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
170         testb $0xff, %cl        /* is NUL char? */
171         jnz L(2)                /* no => process next dword from stopset */
173 #if __BOUNDED_POINTERS__
174         jmp L(1_0)              /* pointer is correct for bounds check */
175 L(1_3): incl %eax               /* adjust pointer for bounds check */
176 L(1_2): incl %eax               /* ditto */
177 L(1_1): incl %eax               /* ditto */
178 L(1_0): CHECK_BOUNDS_HIGH (%eax, DELIM(%esp), jbe)
179 #else
180 L(1_3):; L(1_2):; L(1_1):       /* fall through */
181 #endif
182         leal -4(%edx), %eax     /* prepare loop */
184         /* We use a neat trick for the following loop.  Normally we would
185            have to test for two termination conditions
186            1. a character in the stopset was found
187            and
188            2. the end of the string was found
189            As a sign that the character is in the stopset we store its
190            value in the table.  The value of NUL is NUL so the loop
191            terminates for NUL in every case.  */
193 L(3):   addl $4, %eax           /* adjust pointer for full loop round */
195         movb (%eax), %cl        /* get byte from string */
196         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
197         jz L(4)                 /* no => start of token */
199         movb 1(%eax), %cl       /* get byte from string */
200         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
201         jz L(5)                 /* no => start of token */
203         movb 2(%eax), %cl       /* get byte from string */
204         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
205         jz L(6)                 /* no => start of token */
207         movb 3(%eax), %cl       /* get byte from string */
208         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
209         jnz L(3)                /* yes => start of loop */
211         incl %eax               /* adjust pointer */
212 L(6):   incl %eax
213 L(5):   incl %eax
215         /* Now we have to terminate the string.  */
217 L(4):   leal -4(%eax), %edx     /* We use %EDX for the next run.  */
219 L(7):   addl $4, %edx           /* adjust pointer for full loop round */
221         movb (%edx), %cl        /* get byte from string */
222         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
223         je L(8)                 /* yes => return */
225         movb 1(%edx), %cl       /* get byte from string */
226         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
227         je L(9)                 /* yes => return */
229         movb 2(%edx), %cl       /* get byte from string */
230         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
231         je L(10)                /* yes => return */
233         movb 3(%edx), %cl       /* get byte from string */
234         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
235         jne L(7)                /* no => start loop again */
237         incl %edx               /* adjust pointer */
238 L(10):  incl %edx
239 L(9):   incl %edx
241 L(8):   cmpl %eax, %edx
242         je L(returnNULL)        /* There was no token anymore.  */
244         movb $0, (%edx)         /* Terminate string.  */
246         /* Are we at end of string?  */
247         cmpb $0, %cl
248         leal 1(%edx), %ecx
249         cmovne %ecx, %edx
251         /* Store the pointer to the next character.  */
252 #ifdef USE_AS_STRTOK_R
253         movl SAVE(%esp), %ecx
254 #endif
255         movl %edx, SAVE_PTR
256         CHECK_BOUNDS_HIGH (%edx, SAVE_PTR, jb)
257         RETURN_BOUNDED_POINTER (SAVE_PTR)
259 L(epilogue):
260         /* Remove the stopset table.  */
261         addl $256, %esp
262         cfi_adjust_cfa_offset (-256)
263 #if !defined USE_AS_STRTOK_R && defined PIC
264         popl %ebx
265         cfi_adjust_cfa_offset (-4)
266         cfi_restore (ebx)
267 #endif
268         LEAVE
269         RET_PTR
271 L(returnNULL):
272         xorl %eax, %eax
273 #ifdef USE_AS_STRTOK_R
274         movl SAVE(%esp), %ecx
275 #endif
276         movl %edx, SAVE_PTR
277         RETURN_NULL_BOUNDED_POINTER
278         jmp L(epilogue)
280 END (BP_SYM (FUNCTION))