linux/arch/s390/lib/string.c
<<
>>
Prefs
   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 */
  18static 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
  28static 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 */
  45size_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}
  53EXPORT_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 */
  62size_t strnlen(const char * s, size_t n)
  63{
  64        return __strnend(s, n) - s;
  65}
  66EXPORT_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 */
  75char *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}
  90EXPORT_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 */
 103size_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}
 114EXPORT_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 */
 125char *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}
 132EXPORT_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 */
 141char *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}
 155EXPORT_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 */
 163size_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}
 179EXPORT_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 */
 192char *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}
 201EXPORT_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 */
 212int 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}
 228EXPORT_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 */
 235char * 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}
 246EXPORT_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 */
 253char * 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}
 280EXPORT_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 */
 291void *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}
 304EXPORT_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 */
 312int 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}
 330EXPORT_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 */
 341void *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}
 351EXPORT_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 */
 361void *memcpy(void *dest, const void *src, size_t n)
 362{
 363        return __builtin_memcpy(dest, src, n);
 364}
 365EXPORT_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 */
 375void *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}
 389EXPORT_SYMBOL(memset);
 390