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