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 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'; 101 memcpy(dest, src, len); 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; 119 memset(dest + len, 0, n - len); 120 memcpy(dest, src, len); 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'; 166 memcpy(dest, src, len); 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'; 189 memcpy(p, src, len); 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); 235 return NULL; 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 } 269 return NULL; 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); 343