Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
1da177e4 LT |
2 | * Optimized string functions |
3 | * | |
4 | * S390 version | |
a53c8fab | 5 | * Copyright IBM Corp. 2004 |
1da177e4 LT |
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 | return __strend(s) - s; | |
47 | } | |
48 | EXPORT_SYMBOL(strlen); | |
49 | ||
50 | /** | |
51 | * strnlen - Find the length of a length-limited string | |
52 | * @s: The string to be sized | |
53 | * @n: The maximum number of bytes to search | |
54 | * | |
55 | * returns the minimum of the length of @s and @n | |
56 | */ | |
57 | size_t strnlen(const char * s, size_t n) | |
58 | { | |
59 | return __strnend(s, n) - s; | |
60 | } | |
61 | EXPORT_SYMBOL(strnlen); | |
62 | ||
63 | /** | |
64 | * strcpy - Copy a %NUL terminated string | |
65 | * @dest: Where to copy the string to | |
66 | * @src: Where to copy the string from | |
67 | * | |
68 | * returns a pointer to @dest | |
69 | */ | |
70 | char *strcpy(char *dest, const char *src) | |
71 | { | |
72 | register int r0 asm("0") = 0; | |
73 | char *ret = dest; | |
74 | ||
75 | asm volatile ("0: mvst %0,%1\n" | |
76 | " jo 0b" | |
77 | : "+&a" (dest), "+&a" (src) : "d" (r0) | |
78 | : "cc", "memory" ); | |
79 | return ret; | |
80 | } | |
81 | EXPORT_SYMBOL(strcpy); | |
82 | ||
83 | /** | |
84 | * strlcpy - Copy a %NUL terminated string into a sized buffer | |
85 | * @dest: Where to copy the string to | |
86 | * @src: Where to copy the string from | |
87 | * @size: size of destination buffer | |
88 | * | |
89 | * Compatible with *BSD: the result is always a valid | |
90 | * NUL-terminated string that fits in the buffer (unless, | |
91 | * of course, the buffer size is zero). It does not pad | |
92 | * out the result like strncpy() does. | |
93 | */ | |
94 | size_t strlcpy(char *dest, const char *src, size_t size) | |
95 | { | |
96 | size_t ret = __strend(src) - src; | |
97 | ||
98 | if (size) { | |
99 | size_t len = (ret >= size) ? size-1 : ret; | |
100 | dest[len] = '\0'; | |
535c611d | 101 | memcpy(dest, src, len); |
1da177e4 LT |
102 | } |
103 | return ret; | |
104 | } | |
105 | EXPORT_SYMBOL(strlcpy); | |
106 | ||
107 | /** | |
108 | * strncpy - Copy a length-limited, %NUL-terminated string | |
109 | * @dest: Where to copy the string to | |
110 | * @src: Where to copy the string from | |
111 | * @n: The maximum number of bytes to copy | |
112 | * | |
113 | * The result is not %NUL-terminated if the source exceeds | |
114 | * @n bytes. | |
115 | */ | |
116 | char *strncpy(char *dest, const char *src, size_t n) | |
117 | { | |
118 | size_t len = __strnend(src, n) - src; | |
535c611d HC |
119 | memset(dest + len, 0, n - len); |
120 | memcpy(dest, src, len); | |
1da177e4 LT |
121 | return dest; |
122 | } | |
123 | EXPORT_SYMBOL(strncpy); | |
124 | ||
125 | /** | |
126 | * strcat - Append one %NUL-terminated string to another | |
127 | * @dest: The string to be appended to | |
128 | * @src: The string to append to it | |
129 | * | |
130 | * returns a pointer to @dest | |
131 | */ | |
132 | char *strcat(char *dest, const char *src) | |
133 | { | |
134 | register int r0 asm("0") = 0; | |
135 | unsigned long dummy; | |
136 | char *ret = dest; | |
137 | ||
138 | asm volatile ("0: srst %0,%1\n" | |
139 | " jo 0b\n" | |
140 | "1: mvst %0,%2\n" | |
141 | " jo 1b" | |
142 | : "=&a" (dummy), "+a" (dest), "+a" (src) | |
143 | : "d" (r0), "0" (0UL) : "cc", "memory" ); | |
144 | return ret; | |
145 | } | |
146 | EXPORT_SYMBOL(strcat); | |
147 | ||
148 | /** | |
149 | * strlcat - Append a length-limited, %NUL-terminated string to another | |
150 | * @dest: The string to be appended to | |
151 | * @src: The string to append to it | |
152 | * @n: The size of the destination buffer. | |
153 | */ | |
154 | size_t strlcat(char *dest, const char *src, size_t n) | |
155 | { | |
156 | size_t dsize = __strend(dest) - dest; | |
157 | size_t len = __strend(src) - src; | |
158 | size_t res = dsize + len; | |
159 | ||
160 | if (dsize < n) { | |
161 | dest += dsize; | |
162 | n -= dsize; | |
163 | if (len >= n) | |
164 | len = n - 1; | |
165 | dest[len] = '\0'; | |
535c611d | 166 | memcpy(dest, src, len); |
1da177e4 LT |
167 | } |
168 | return res; | |
169 | } | |
170 | EXPORT_SYMBOL(strlcat); | |
171 | ||
172 | /** | |
173 | * strncat - Append a length-limited, %NUL-terminated string to another | |
174 | * @dest: The string to be appended to | |
175 | * @src: The string to append to it | |
176 | * @n: The maximum numbers of bytes to copy | |
177 | * | |
178 | * returns a pointer to @dest | |
179 | * | |
180 | * Note that in contrast to strncpy, strncat ensures the result is | |
181 | * terminated. | |
182 | */ | |
183 | char *strncat(char *dest, const char *src, size_t n) | |
184 | { | |
185 | size_t len = __strnend(src, n) - src; | |
186 | char *p = __strend(dest); | |
187 | ||
188 | p[len] = '\0'; | |
535c611d | 189 | memcpy(p, src, len); |
1da177e4 LT |
190 | return dest; |
191 | } | |
192 | EXPORT_SYMBOL(strncat); | |
193 | ||
194 | /** | |
195 | * strcmp - Compare two strings | |
196 | * @cs: One string | |
197 | * @ct: Another string | |
198 | * | |
199 | * returns 0 if @cs and @ct are equal, | |
200 | * < 0 if @cs is less than @ct | |
201 | * > 0 if @cs is greater than @ct | |
202 | */ | |
203 | int strcmp(const char *cs, const char *ct) | |
204 | { | |
205 | register int r0 asm("0") = 0; | |
206 | int ret = 0; | |
207 | ||
208 | asm volatile ("0: clst %2,%3\n" | |
209 | " jo 0b\n" | |
210 | " je 1f\n" | |
211 | " ic %0,0(%2)\n" | |
212 | " ic %1,0(%3)\n" | |
213 | " sr %0,%1\n" | |
214 | "1:" | |
215 | : "+d" (ret), "+d" (r0), "+a" (cs), "+a" (ct) | |
216 | : : "cc" ); | |
217 | return ret; | |
218 | } | |
219 | EXPORT_SYMBOL(strcmp); | |
220 | ||
221 | /** | |
222 | * strrchr - Find the last occurrence of a character in a string | |
223 | * @s: The string to be searched | |
224 | * @c: The character to search for | |
225 | */ | |
226 | char * strrchr(const char * s, int c) | |
227 | { | |
228 | size_t len = __strend(s) - s; | |
229 | ||
230 | if (len) | |
231 | do { | |
232 | if (s[len] == (char) c) | |
233 | return (char *) s + len; | |
234 | } while (--len > 0); | |
d2c993d8 | 235 | return NULL; |
1da177e4 LT |
236 | } |
237 | EXPORT_SYMBOL(strrchr); | |
238 | ||
239 | /** | |
240 | * strstr - Find the first substring in a %NUL terminated string | |
241 | * @s1: The string to be searched | |
242 | * @s2: The string to search for | |
243 | */ | |
244 | char * strstr(const char * s1,const char * s2) | |
245 | { | |
246 | int l1, l2; | |
247 | ||
248 | l2 = __strend(s2) - s2; | |
249 | if (!l2) | |
250 | return (char *) s1; | |
251 | l1 = __strend(s1) - s1; | |
252 | while (l1-- >= l2) { | |
253 | register unsigned long r2 asm("2") = (unsigned long) s1; | |
254 | register unsigned long r3 asm("3") = (unsigned long) l2; | |
255 | register unsigned long r4 asm("4") = (unsigned long) s2; | |
256 | register unsigned long r5 asm("5") = (unsigned long) l2; | |
257 | int cc; | |
258 | ||
259 | asm volatile ("0: clcle %1,%3,0\n" | |
260 | " jo 0b\n" | |
261 | " ipm %0\n" | |
262 | " srl %0,28" | |
263 | : "=&d" (cc), "+a" (r2), "+a" (r3), | |
264 | "+a" (r4), "+a" (r5) : : "cc" ); | |
265 | if (!cc) | |
266 | return (char *) s1; | |
267 | s1++; | |
268 | } | |
d2c993d8 | 269 | return NULL; |
1da177e4 LT |
270 | } |
271 | EXPORT_SYMBOL(strstr); | |
272 | ||
273 | /** | |
274 | * memchr - Find a character in an area of memory. | |
275 | * @s: The memory area | |
276 | * @c: The byte to search for | |
277 | * @n: The size of the area. | |
278 | * | |
279 | * returns the address of the first occurrence of @c, or %NULL | |
280 | * if @c is not found | |
281 | */ | |
282 | void *memchr(const void *s, int c, size_t n) | |
283 | { | |
284 | register int r0 asm("0") = (char) c; | |
285 | const void *ret = s + n; | |
286 | ||
287 | asm volatile ("0: srst %0,%1\n" | |
288 | " jo 0b\n" | |
289 | " jl 1f\n" | |
290 | " la %0,0\n" | |
291 | "1:" | |
292 | : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" ); | |
293 | return (void *) ret; | |
294 | } | |
295 | EXPORT_SYMBOL(memchr); | |
296 | ||
297 | /** | |
298 | * memcmp - Compare two areas of memory | |
299 | * @cs: One area of memory | |
300 | * @ct: Another area of memory | |
301 | * @count: The size of the area. | |
302 | */ | |
303 | int memcmp(const void *cs, const void *ct, size_t n) | |
304 | { | |
305 | register unsigned long r2 asm("2") = (unsigned long) cs; | |
306 | register unsigned long r3 asm("3") = (unsigned long) n; | |
307 | register unsigned long r4 asm("4") = (unsigned long) ct; | |
308 | register unsigned long r5 asm("5") = (unsigned long) n; | |
309 | int ret; | |
310 | ||
311 | asm volatile ("0: clcle %1,%3,0\n" | |
312 | " jo 0b\n" | |
313 | " ipm %0\n" | |
314 | " srl %0,28" | |
315 | : "=&d" (ret), "+a" (r2), "+a" (r3), "+a" (r4), "+a" (r5) | |
316 | : : "cc" ); | |
317 | if (ret) | |
318 | ret = *(char *) r2 - *(char *) r4; | |
319 | return ret; | |
320 | } | |
321 | EXPORT_SYMBOL(memcmp); | |
322 | ||
323 | /** | |
324 | * memscan - Find a character in an area of memory. | |
325 | * @s: The memory area | |
326 | * @c: The byte to search for | |
327 | * @n: The size of the area. | |
328 | * | |
329 | * returns the address of the first occurrence of @c, or 1 byte past | |
330 | * the area if @c is not found | |
331 | */ | |
332 | void *memscan(void *s, int c, size_t n) | |
333 | { | |
334 | register int r0 asm("0") = (char) c; | |
335 | const void *ret = s + n; | |
336 | ||
337 | asm volatile ("0: srst %0,%1\n" | |
338 | " jo 0b\n" | |
339 | : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" ); | |
340 | return (void *) ret; | |
341 | } | |
342 | EXPORT_SYMBOL(memscan); |