root/arch/s390/lib/string.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __strend
  2. __strnend
  3. strlen
  4. strnlen
  5. strcpy
  6. strlcpy
  7. strncpy
  8. strcat
  9. strlcat
  10. strncat
  11. strcmp
  12. strrchr
  13. clcle
  14. strstr
  15. memchr
  16. memcmp
  17. memscan

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  *    Optimized string functions
   4  *
   5  *  S390 version
   6  *    Copyright IBM Corp. 2004
   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/string.h>
  14 #include <linux/export.h>
  15 
  16 /*
  17  * Helper functions to find the end of a string
  18  */
  19 static inline char *__strend(const char *s)
  20 {
  21         register unsigned long r0 asm("0") = 0;
  22 
  23         asm volatile ("0: srst  %0,%1\n"
  24                       "   jo    0b"
  25                       : "+d" (r0), "+a" (s) :  : "cc", "memory");
  26         return (char *) r0;
  27 }
  28 
  29 static inline char *__strnend(const char *s, size_t n)
  30 {
  31         register unsigned long r0 asm("0") = 0;
  32         const char *p = s + n;
  33 
  34         asm volatile ("0: srst  %0,%1\n"
  35                       "   jo    0b"
  36                       : "+d" (p), "+a" (s) : "d" (r0) : "cc", "memory");
  37         return (char *) p;
  38 }
  39 
  40 /**
  41  * strlen - Find the length of a string
  42  * @s: The string to be sized
  43  *
  44  * returns the length of @s
  45  */
  46 #ifdef __HAVE_ARCH_STRLEN
  47 size_t strlen(const char *s)
  48 {
  49         return __strend(s) - s;
  50 }
  51 EXPORT_SYMBOL(strlen);
  52 #endif
  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 #ifdef __HAVE_ARCH_STRNLEN
  62 size_t strnlen(const char *s, size_t n)
  63 {
  64         return __strnend(s, n) - s;
  65 }
  66 EXPORT_SYMBOL(strnlen);
  67 #endif
  68 
  69 /**
  70  * strcpy - Copy a %NUL terminated string
  71  * @dest: Where to copy the string to
  72  * @src: Where to copy the string from
  73  *
  74  * returns a pointer to @dest
  75  */
  76 #ifdef __HAVE_ARCH_STRCPY
  77 char *strcpy(char *dest, const char *src)
  78 {
  79         register int r0 asm("0") = 0;
  80         char *ret = dest;
  81 
  82         asm volatile ("0: mvst  %0,%1\n"
  83                       "   jo    0b"
  84                       : "+&a" (dest), "+&a" (src) : "d" (r0)
  85                       : "cc", "memory" );
  86         return ret;
  87 }
  88 EXPORT_SYMBOL(strcpy);
  89 #endif
  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 #ifdef __HAVE_ARCH_STRLCPY
 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                 memcpy(dest, src, len);
 111         }
 112         return ret;
 113 }
 114 EXPORT_SYMBOL(strlcpy);
 115 #endif
 116 
 117 /**
 118  * strncpy - Copy a length-limited, %NUL-terminated string
 119  * @dest: Where to copy the string to
 120  * @src: Where to copy the string from
 121  * @n: The maximum number of bytes to copy
 122  *
 123  * The result is not %NUL-terminated if the source exceeds
 124  * @n bytes.
 125  */
 126 #ifdef __HAVE_ARCH_STRNCPY
 127 char *strncpy(char *dest, const char *src, size_t n)
 128 {
 129         size_t len = __strnend(src, n) - src;
 130         memset(dest + len, 0, n - len);
 131         memcpy(dest, src, len);
 132         return dest;
 133 }
 134 EXPORT_SYMBOL(strncpy);
 135 #endif
 136 
 137 /**
 138  * strcat - Append one %NUL-terminated string to another
 139  * @dest: The string to be appended to
 140  * @src: The string to append to it
 141  *
 142  * returns a pointer to @dest
 143  */
 144 #ifdef __HAVE_ARCH_STRCAT
 145 char *strcat(char *dest, const char *src)
 146 {
 147         register int r0 asm("0") = 0;
 148         unsigned long dummy;
 149         char *ret = dest;
 150 
 151         asm volatile ("0: srst  %0,%1\n"
 152                       "   jo    0b\n"
 153                       "1: mvst  %0,%2\n"
 154                       "   jo    1b"
 155                       : "=&a" (dummy), "+a" (dest), "+a" (src)
 156                       : "d" (r0), "0" (0UL) : "cc", "memory" );
 157         return ret;
 158 }
 159 EXPORT_SYMBOL(strcat);
 160 #endif
 161 
 162 /**
 163  * strlcat - Append a length-limited, %NUL-terminated string to another
 164  * @dest: The string to be appended to
 165  * @src: The string to append to it
 166  * @n: The size of the destination buffer.
 167  */
 168 #ifdef __HAVE_ARCH_STRLCAT
 169 size_t strlcat(char *dest, const char *src, size_t n)
 170 {
 171         size_t dsize = __strend(dest) - dest;
 172         size_t len = __strend(src) - src;
 173         size_t res = dsize + len;
 174 
 175         if (dsize < n) {
 176                 dest += dsize;
 177                 n -= dsize;
 178                 if (len >= n)
 179                         len = n - 1;
 180                 dest[len] = '\0';
 181                 memcpy(dest, src, len);
 182         }
 183         return res;
 184 }
 185 EXPORT_SYMBOL(strlcat);
 186 #endif
 187 
 188 /**
 189  * strncat - Append a length-limited, %NUL-terminated string to another
 190  * @dest: The string to be appended to
 191  * @src: The string to append to it
 192  * @n: The maximum numbers of bytes to copy
 193  *
 194  * returns a pointer to @dest
 195  *
 196  * Note that in contrast to strncpy, strncat ensures the result is
 197  * terminated.
 198  */
 199 #ifdef __HAVE_ARCH_STRNCAT
 200 char *strncat(char *dest, const char *src, size_t n)
 201 {
 202         size_t len = __strnend(src, n) - src;
 203         char *p = __strend(dest);
 204 
 205         p[len] = '\0';
 206         memcpy(p, src, len);
 207         return dest;
 208 }
 209 EXPORT_SYMBOL(strncat);
 210 #endif
 211 
 212 /**
 213  * strcmp - Compare two strings
 214  * @s1: One string
 215  * @s2: Another string
 216  *
 217  * returns   0 if @s1 and @s2 are equal,
 218  *         < 0 if @s1 is less than @s2
 219  *         > 0 if @s1 is greater than @s2
 220  */
 221 #ifdef __HAVE_ARCH_STRCMP
 222 int strcmp(const char *s1, const char *s2)
 223 {
 224         register int r0 asm("0") = 0;
 225         int ret = 0;
 226 
 227         asm volatile ("0: clst %2,%3\n"
 228                       "   jo   0b\n"
 229                       "   je   1f\n"
 230                       "   ic   %0,0(%2)\n"
 231                       "   ic   %1,0(%3)\n"
 232                       "   sr   %0,%1\n"
 233                       "1:"
 234                       : "+d" (ret), "+d" (r0), "+a" (s1), "+a" (s2)
 235                       : : "cc", "memory");
 236         return ret;
 237 }
 238 EXPORT_SYMBOL(strcmp);
 239 #endif
 240 
 241 /**
 242  * strrchr - Find the last occurrence of a character in a string
 243  * @s: The string to be searched
 244  * @c: The character to search for
 245  */
 246 #ifdef __HAVE_ARCH_STRRCHR
 247 char *strrchr(const char *s, int c)
 248 {
 249        size_t len = __strend(s) - s;
 250 
 251        if (len)
 252                do {
 253                        if (s[len] == (char) c)
 254                                return (char *) s + len;
 255                } while (--len > 0);
 256        return NULL;
 257 }
 258 EXPORT_SYMBOL(strrchr);
 259 #endif
 260 
 261 static inline int clcle(const char *s1, unsigned long l1,
 262                         const char *s2, unsigned long l2)
 263 {
 264         register unsigned long r2 asm("2") = (unsigned long) s1;
 265         register unsigned long r3 asm("3") = (unsigned long) l1;
 266         register unsigned long r4 asm("4") = (unsigned long) s2;
 267         register unsigned long r5 asm("5") = (unsigned long) l2;
 268         int cc;
 269 
 270         asm volatile ("0: clcle %1,%3,0\n"
 271                       "   jo    0b\n"
 272                       "   ipm   %0\n"
 273                       "   srl   %0,28"
 274                       : "=&d" (cc), "+a" (r2), "+a" (r3),
 275                         "+a" (r4), "+a" (r5) : : "cc", "memory");
 276         return cc;
 277 }
 278 
 279 /**
 280  * strstr - Find the first substring in a %NUL terminated string
 281  * @s1: The string to be searched
 282  * @s2: The string to search for
 283  */
 284 #ifdef __HAVE_ARCH_STRSTR
 285 char *strstr(const char *s1, const char *s2)
 286 {
 287         int l1, l2;
 288 
 289         l2 = __strend(s2) - s2;
 290         if (!l2)
 291                 return (char *) s1;
 292         l1 = __strend(s1) - s1;
 293         while (l1-- >= l2) {
 294                 int cc;
 295 
 296                 cc = clcle(s1, l2, s2, l2);
 297                 if (!cc)
 298                         return (char *) s1;
 299                 s1++;
 300         }
 301         return NULL;
 302 }
 303 EXPORT_SYMBOL(strstr);
 304 #endif
 305 
 306 /**
 307  * memchr - Find a character in an area of memory.
 308  * @s: The memory area
 309  * @c: The byte to search for
 310  * @n: The size of the area.
 311  *
 312  * returns the address of the first occurrence of @c, or %NULL
 313  * if @c is not found
 314  */
 315 #ifdef __HAVE_ARCH_MEMCHR
 316 void *memchr(const void *s, int c, size_t n)
 317 {
 318         register int r0 asm("0") = (char) c;
 319         const void *ret = s + n;
 320 
 321         asm volatile ("0: srst  %0,%1\n"
 322                       "   jo    0b\n"
 323                       "   jl    1f\n"
 324                       "   la    %0,0\n"
 325                       "1:"
 326                       : "+a" (ret), "+&a" (s) : "d" (r0) : "cc", "memory");
 327         return (void *) ret;
 328 }
 329 EXPORT_SYMBOL(memchr);
 330 #endif
 331 
 332 /**
 333  * memcmp - Compare two areas of memory
 334  * @s1: One area of memory
 335  * @s2: Another area of memory
 336  * @count: The size of the area.
 337  */
 338 #ifdef __HAVE_ARCH_MEMCMP
 339 int memcmp(const void *s1, const void *s2, size_t n)
 340 {
 341         int ret;
 342 
 343         ret = clcle(s1, n, s2, n);
 344         if (ret)
 345                 ret = ret == 1 ? -1 : 1;
 346         return ret;
 347 }
 348 EXPORT_SYMBOL(memcmp);
 349 #endif
 350 
 351 /**
 352  * memscan - Find a character in an area of memory.
 353  * @s: The memory area
 354  * @c: The byte to search for
 355  * @n: The size of the area.
 356  *
 357  * returns the address of the first occurrence of @c, or 1 byte past
 358  * the area if @c is not found
 359  */
 360 #ifdef __HAVE_ARCH_MEMSCAN
 361 void *memscan(void *s, int c, size_t n)
 362 {
 363         register int r0 asm("0") = (char) c;
 364         const void *ret = s + n;
 365 
 366         asm volatile ("0: srst  %0,%1\n"
 367                       "   jo    0b\n"
 368                       : "+a" (ret), "+&a" (s) : "d" (r0) : "cc", "memory");
 369         return (void *) ret;
 370 }
 371 EXPORT_SYMBOL(memscan);
 372 #endif

/* [<][>][^][v][top][bottom][index][help] */