]> Pileus Git - ~andy/linux/blob - arch/s390/lib/string.c
Merge branch 'fortglx/3.7/time' of git://git.linaro.org/people/jstultz/linux into...
[~andy/linux] / arch / s390 / lib / string.c
1 /*
2  *    Optimized string functions
3  *
4  *  S390 version
5  *    Copyright IBM Corp. 2004
6  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
7  */
8
9 #define IN_ARCH_STRING_C 1
10
11 #include <linux/types.h>
12 #include <linux/module.h>
13
14 /*
15  * Helper functions to find the end of a string
16  */
17 static inline char *__strend(const char *s)
18 {
19         register unsigned long r0 asm("0") = 0;
20
21         asm volatile ("0: srst  %0,%1\n"
22                       "   jo    0b"
23                       : "+d" (r0), "+a" (s) :  : "cc" );
24         return (char *) r0;
25 }
26
27 static inline char *__strnend(const char *s, size_t n)
28 {
29         register unsigned long r0 asm("0") = 0;
30         const char *p = s + n;
31
32         asm volatile ("0: srst  %0,%1\n"
33                       "   jo    0b"
34                       : "+d" (p), "+a" (s) : "d" (r0) : "cc" );
35         return (char *) p;
36 }
37
38 /**
39  * strlen - Find the length of a string
40  * @s: The string to be sized
41  *
42  * returns the length of @s
43  */
44 size_t strlen(const char *s)
45 {
46 #if __GNUC__ < 4
47         return __strend(s) - s;
48 #else
49         return __builtin_strlen(s);
50 #endif
51 }
52 EXPORT_SYMBOL(strlen);
53
54 /**
55  * strnlen - Find the length of a length-limited string
56  * @s: The string to be sized
57  * @n: The maximum number of bytes to search
58  *
59  * returns the minimum of the length of @s and @n
60  */
61 size_t strnlen(const char * s, size_t n)
62 {
63         return __strnend(s, n) - s;
64 }
65 EXPORT_SYMBOL(strnlen);
66
67 /**
68  * strcpy - Copy a %NUL terminated string
69  * @dest: Where to copy the string to
70  * @src: Where to copy the string from
71  *
72  * returns a pointer to @dest
73  */
74 char *strcpy(char *dest, const char *src)
75 {
76 #if __GNUC__ < 4
77         register int r0 asm("0") = 0;
78         char *ret = dest;
79
80         asm volatile ("0: mvst  %0,%1\n"
81                       "   jo    0b"
82                       : "+&a" (dest), "+&a" (src) : "d" (r0)
83                       : "cc", "memory" );
84         return ret;
85 #else
86         return __builtin_strcpy(dest, src);
87 #endif
88 }
89 EXPORT_SYMBOL(strcpy);
90
91 /**
92  * strlcpy - Copy a %NUL terminated string into a sized buffer
93  * @dest: Where to copy the string to
94  * @src: Where to copy the string from
95  * @size: size of destination buffer
96  *
97  * Compatible with *BSD: the result is always a valid
98  * NUL-terminated string that fits in the buffer (unless,
99  * of course, the buffer size is zero). It does not pad
100  * out the result like strncpy() does.
101  */
102 size_t strlcpy(char *dest, const char *src, size_t size)
103 {
104         size_t ret = __strend(src) - src;
105
106         if (size) {
107                 size_t len = (ret >= size) ? size-1 : ret;
108                 dest[len] = '\0';
109                 __builtin_memcpy(dest, src, len);
110         }
111         return ret;
112 }
113 EXPORT_SYMBOL(strlcpy);
114
115 /**
116  * strncpy - Copy a length-limited, %NUL-terminated string
117  * @dest: Where to copy the string to
118  * @src: Where to copy the string from
119  * @n: The maximum number of bytes to copy
120  *
121  * The result is not %NUL-terminated if the source exceeds
122  * @n bytes.
123  */
124 char *strncpy(char *dest, const char *src, size_t n)
125 {
126         size_t len = __strnend(src, n) - src;
127         __builtin_memset(dest + len, 0, n - len);
128         __builtin_memcpy(dest, src, len);
129         return dest;
130 }
131 EXPORT_SYMBOL(strncpy);
132
133 /**
134  * strcat - Append one %NUL-terminated string to another
135  * @dest: The string to be appended to
136  * @src: The string to append to it
137  *
138  * returns a pointer to @dest
139  */
140 char *strcat(char *dest, const char *src)
141 {
142         register int r0 asm("0") = 0;
143         unsigned long dummy;
144         char *ret = dest;
145
146         asm volatile ("0: srst  %0,%1\n"
147                       "   jo    0b\n"
148                       "1: mvst  %0,%2\n"
149                       "   jo    1b"
150                       : "=&a" (dummy), "+a" (dest), "+a" (src)
151                       : "d" (r0), "0" (0UL) : "cc", "memory" );
152         return ret;
153 }
154 EXPORT_SYMBOL(strcat);
155
156 /**
157  * strlcat - Append a length-limited, %NUL-terminated string to another
158  * @dest: The string to be appended to
159  * @src: The string to append to it
160  * @n: The size of the destination buffer.
161  */
162 size_t strlcat(char *dest, const char *src, size_t n)
163 {
164         size_t dsize = __strend(dest) - dest;
165         size_t len = __strend(src) - src;
166         size_t res = dsize + len;
167
168         if (dsize < n) {
169                 dest += dsize;
170                 n -= dsize;
171                 if (len >= n)
172                         len = n - 1;
173                 dest[len] = '\0';
174                 __builtin_memcpy(dest, src, len);
175         }
176         return res;
177 }
178 EXPORT_SYMBOL(strlcat);
179
180 /**
181  * strncat - Append a length-limited, %NUL-terminated string to another
182  * @dest: The string to be appended to
183  * @src: The string to append to it
184  * @n: The maximum numbers of bytes to copy
185  *
186  * returns a pointer to @dest
187  *
188  * Note that in contrast to strncpy, strncat ensures the result is
189  * terminated.
190  */
191 char *strncat(char *dest, const char *src, size_t n)
192 {
193         size_t len = __strnend(src, n) - src;
194         char *p = __strend(dest);
195
196         p[len] = '\0';
197         __builtin_memcpy(p, src, len);
198         return dest;
199 }
200 EXPORT_SYMBOL(strncat);
201
202 /**
203  * strcmp - Compare two strings
204  * @cs: One string
205  * @ct: Another string
206  *
207  * returns   0 if @cs and @ct are equal,
208  *         < 0 if @cs is less than @ct
209  *         > 0 if @cs is greater than @ct
210  */
211 int strcmp(const char *cs, const char *ct)
212 {
213         register int r0 asm("0") = 0;
214         int ret = 0;
215
216         asm volatile ("0: clst %2,%3\n"
217                       "   jo   0b\n"
218                       "   je   1f\n"
219                       "   ic   %0,0(%2)\n"
220                       "   ic   %1,0(%3)\n"
221                       "   sr   %0,%1\n"
222                       "1:"
223                       : "+d" (ret), "+d" (r0), "+a" (cs), "+a" (ct)
224                       : : "cc" );
225         return ret;
226 }
227 EXPORT_SYMBOL(strcmp);
228
229 /**
230  * strrchr - Find the last occurrence of a character in a string
231  * @s: The string to be searched
232  * @c: The character to search for
233  */
234 char * strrchr(const char * s, int c)
235 {
236        size_t len = __strend(s) - s;
237
238        if (len)
239                do {
240                        if (s[len] == (char) c)
241                                return (char *) s + len;
242                } while (--len > 0);
243        return NULL;
244 }
245 EXPORT_SYMBOL(strrchr);
246
247 /**
248  * strstr - Find the first substring in a %NUL terminated string
249  * @s1: The string to be searched
250  * @s2: The string to search for
251  */
252 char * strstr(const char * s1,const char * s2)
253 {
254         int l1, l2;
255
256         l2 = __strend(s2) - s2;
257         if (!l2)
258                 return (char *) s1;
259         l1 = __strend(s1) - s1;
260         while (l1-- >= l2) {
261                 register unsigned long r2 asm("2") = (unsigned long) s1;
262                 register unsigned long r3 asm("3") = (unsigned long) l2;
263                 register unsigned long r4 asm("4") = (unsigned long) s2;
264                 register unsigned long r5 asm("5") = (unsigned long) l2;
265                 int cc;
266
267                 asm volatile ("0: clcle %1,%3,0\n"
268                               "   jo    0b\n"
269                               "   ipm   %0\n"
270                               "   srl   %0,28"
271                               : "=&d" (cc), "+a" (r2), "+a" (r3),
272                                 "+a" (r4), "+a" (r5) : : "cc" );
273                 if (!cc)
274                         return (char *) s1;
275                 s1++;
276         }
277         return NULL;
278 }
279 EXPORT_SYMBOL(strstr);
280
281 /**
282  * memchr - Find a character in an area of memory.
283  * @s: The memory area
284  * @c: The byte to search for
285  * @n: The size of the area.
286  *
287  * returns the address of the first occurrence of @c, or %NULL
288  * if @c is not found
289  */
290 void *memchr(const void *s, int c, size_t n)
291 {
292         register int r0 asm("0") = (char) c;
293         const void *ret = s + n;
294
295         asm volatile ("0: srst  %0,%1\n"
296                       "   jo    0b\n"
297                       "   jl    1f\n"
298                       "   la    %0,0\n"
299                       "1:"
300                       : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" );
301         return (void *) ret;
302 }
303 EXPORT_SYMBOL(memchr);
304
305 /**
306  * memcmp - Compare two areas of memory
307  * @cs: One area of memory
308  * @ct: Another area of memory
309  * @count: The size of the area.
310  */
311 int memcmp(const void *cs, const void *ct, size_t n)
312 {
313         register unsigned long r2 asm("2") = (unsigned long) cs;
314         register unsigned long r3 asm("3") = (unsigned long) n;
315         register unsigned long r4 asm("4") = (unsigned long) ct;
316         register unsigned long r5 asm("5") = (unsigned long) n;
317         int ret;
318
319         asm volatile ("0: clcle %1,%3,0\n"
320                       "   jo    0b\n"
321                       "   ipm   %0\n"
322                       "   srl   %0,28"
323                       : "=&d" (ret), "+a" (r2), "+a" (r3), "+a" (r4), "+a" (r5)
324                       : : "cc" );
325         if (ret)
326                 ret = *(char *) r2 - *(char *) r4;
327         return ret;
328 }
329 EXPORT_SYMBOL(memcmp);
330
331 /**
332  * memscan - Find a character in an area of memory.
333  * @s: The memory area
334  * @c: The byte to search for
335  * @n: The size of the area.
336  *
337  * returns the address of the first occurrence of @c, or 1 byte past
338  * the area if @c is not found
339  */
340 void *memscan(void *s, int c, size_t n)
341 {
342         register int r0 asm("0") = (char) c;
343         const void *ret = s + n;
344
345         asm volatile ("0: srst  %0,%1\n"
346                       "   jo    0b\n"
347                       : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" );
348         return (void *) ret;
349 }
350 EXPORT_SYMBOL(memscan);
351
352 /**
353  * memcpy - Copy one area of memory to another
354  * @dest: Where to copy to
355  * @src: Where to copy from
356  * @n: The size of the area.
357  *
358  * returns a pointer to @dest
359  */
360 void *memcpy(void *dest, const void *src, size_t n)
361 {
362         return __builtin_memcpy(dest, src, n);
363 }
364 EXPORT_SYMBOL(memcpy);
365
366 /**
367  * memset - Fill a region of memory with the given value
368  * @s: Pointer to the start of the area.
369  * @c: The byte to fill the area with
370  * @n: The size of the area.
371  *
372  * returns a pointer to @s
373  */
374 void *memset(void *s, int c, size_t n)
375 {
376         char *xs;
377
378         if (c == 0)
379                 return __builtin_memset(s, 0, n);
380
381         xs = (char *) s;
382         if (n > 0)
383                 do {
384                         *xs++ = c;
385                 } while (--n > 0);
386         return s;
387 }
388 EXPORT_SYMBOL(memset);