Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
string.c
Go to the documentation of this file.
1 /*
2  * Optimized string functions
3  *
4  * S390 version
5  * Copyright IBM Corp. 2004
6  * Author(s): Martin Schwidefsky ([email protected])
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 
44 size_t strlen(const char *s)
45 {
46  return __strend(s) - s;
47 }
49 
57 size_t strnlen(const char * s, size_t n)
58 {
59  return __strnend(s, n) - s;
60 }
61 EXPORT_SYMBOL(strnlen);
62 
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 }
82 
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';
101  memcpy(dest, src, len);
102  }
103  return ret;
104 }
106 
116 char *strncpy(char *dest, const char *src, size_t n)
117 {
118  size_t len = __strnend(src, n) - src;
119  memset(dest + len, 0, n - len);
120  memcpy(dest, src, len);
121  return dest;
122 }
123 EXPORT_SYMBOL(strncpy);
124 
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 }
147 
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';
166  memcpy(dest, src, len);
167  }
168  return res;
169 }
171 
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';
189  memcpy(p, src, len);
190  return dest;
191 }
193 
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 }
220 
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);
235  return NULL;
236 }
238 
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  }
269  return NULL;
270 }
272 
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 }
296 
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 }
322 
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);