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