string.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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. #define IN_ARCH_STRING_C 1
  10. #include <linux/types.h>
  11. #include <linux/string.h>
  12. #include <linux/export.h>
  13. /*
  14. * Helper functions to find the end of a string
  15. */
  16. static inline char *__strend(const char *s)
  17. {
  18. register unsigned long r0 asm("0") = 0;
  19. asm volatile ("0: srst %0,%1\n"
  20. " jo 0b"
  21. : "+d" (r0), "+a" (s) : : "cc", "memory");
  22. return (char *) r0;
  23. }
  24. static inline char *__strnend(const char *s, size_t n)
  25. {
  26. register unsigned long r0 asm("0") = 0;
  27. const char *p = s + n;
  28. asm volatile ("0: srst %0,%1\n"
  29. " jo 0b"
  30. : "+d" (p), "+a" (s) : "d" (r0) : "cc", "memory");
  31. return (char *) p;
  32. }
  33. /**
  34. * strlen - Find the length of a string
  35. * @s: The string to be sized
  36. *
  37. * returns the length of @s
  38. */
  39. size_t strlen(const char *s)
  40. {
  41. return __strend(s) - s;
  42. }
  43. EXPORT_SYMBOL(strlen);
  44. /**
  45. * strnlen - Find the length of a length-limited string
  46. * @s: The string to be sized
  47. * @n: The maximum number of bytes to search
  48. *
  49. * returns the minimum of the length of @s and @n
  50. */
  51. size_t strnlen(const char *s, size_t n)
  52. {
  53. return __strnend(s, n) - s;
  54. }
  55. EXPORT_SYMBOL(strnlen);
  56. /**
  57. * strcpy - Copy a %NUL terminated string
  58. * @dest: Where to copy the string to
  59. * @src: Where to copy the string from
  60. *
  61. * returns a pointer to @dest
  62. */
  63. char *strcpy(char *dest, const char *src)
  64. {
  65. register int r0 asm("0") = 0;
  66. char *ret = dest;
  67. asm volatile ("0: mvst %0,%1\n"
  68. " jo 0b"
  69. : "+&a" (dest), "+&a" (src) : "d" (r0)
  70. : "cc", "memory" );
  71. return ret;
  72. }
  73. EXPORT_SYMBOL(strcpy);
  74. /**
  75. * strlcpy - Copy a %NUL terminated string into a sized buffer
  76. * @dest: Where to copy the string to
  77. * @src: Where to copy the string from
  78. * @size: size of destination buffer
  79. *
  80. * Compatible with *BSD: the result is always a valid
  81. * NUL-terminated string that fits in the buffer (unless,
  82. * of course, the buffer size is zero). It does not pad
  83. * out the result like strncpy() does.
  84. */
  85. size_t strlcpy(char *dest, const char *src, size_t size)
  86. {
  87. size_t ret = __strend(src) - src;
  88. if (size) {
  89. size_t len = (ret >= size) ? size-1 : ret;
  90. dest[len] = '\0';
  91. memcpy(dest, src, len);
  92. }
  93. return ret;
  94. }
  95. EXPORT_SYMBOL(strlcpy);
  96. /**
  97. * strncpy - Copy a length-limited, %NUL-terminated string
  98. * @dest: Where to copy the string to
  99. * @src: Where to copy the string from
  100. * @n: The maximum number of bytes to copy
  101. *
  102. * The result is not %NUL-terminated if the source exceeds
  103. * @n bytes.
  104. */
  105. char *strncpy(char *dest, const char *src, size_t n)
  106. {
  107. size_t len = __strnend(src, n) - src;
  108. memset(dest + len, 0, n - len);
  109. memcpy(dest, src, len);
  110. return dest;
  111. }
  112. EXPORT_SYMBOL(strncpy);
  113. /**
  114. * strcat - Append one %NUL-terminated string to another
  115. * @dest: The string to be appended to
  116. * @src: The string to append to it
  117. *
  118. * returns a pointer to @dest
  119. */
  120. char *strcat(char *dest, const char *src)
  121. {
  122. register int r0 asm("0") = 0;
  123. unsigned long dummy;
  124. char *ret = dest;
  125. asm volatile ("0: srst %0,%1\n"
  126. " jo 0b\n"
  127. "1: mvst %0,%2\n"
  128. " jo 1b"
  129. : "=&a" (dummy), "+a" (dest), "+a" (src)
  130. : "d" (r0), "0" (0UL) : "cc", "memory" );
  131. return ret;
  132. }
  133. EXPORT_SYMBOL(strcat);
  134. /**
  135. * strlcat - Append a length-limited, %NUL-terminated string to another
  136. * @dest: The string to be appended to
  137. * @src: The string to append to it
  138. * @n: The size of the destination buffer.
  139. */
  140. size_t strlcat(char *dest, const char *src, size_t n)
  141. {
  142. size_t dsize = __strend(dest) - dest;
  143. size_t len = __strend(src) - src;
  144. size_t res = dsize + len;
  145. if (dsize < n) {
  146. dest += dsize;
  147. n -= dsize;
  148. if (len >= n)
  149. len = n - 1;
  150. dest[len] = '\0';
  151. memcpy(dest, src, len);
  152. }
  153. return res;
  154. }
  155. EXPORT_SYMBOL(strlcat);
  156. /**
  157. * strncat - Append a length-limited, %NUL-terminated string to another
  158. * @dest: The string to be appended to
  159. * @src: The string to append to it
  160. * @n: The maximum numbers of bytes to copy
  161. *
  162. * returns a pointer to @dest
  163. *
  164. * Note that in contrast to strncpy, strncat ensures the result is
  165. * terminated.
  166. */
  167. char *strncat(char *dest, const char *src, size_t n)
  168. {
  169. size_t len = __strnend(src, n) - src;
  170. char *p = __strend(dest);
  171. p[len] = '\0';
  172. memcpy(p, src, len);
  173. return dest;
  174. }
  175. EXPORT_SYMBOL(strncat);
  176. /**
  177. * strcmp - Compare two strings
  178. * @s1: One string
  179. * @s2: Another string
  180. *
  181. * returns 0 if @s1 and @s2 are equal,
  182. * < 0 if @s1 is less than @s2
  183. * > 0 if @s1 is greater than @s2
  184. */
  185. int strcmp(const char *s1, const char *s2)
  186. {
  187. register int r0 asm("0") = 0;
  188. int ret = 0;
  189. asm volatile ("0: clst %2,%3\n"
  190. " jo 0b\n"
  191. " je 1f\n"
  192. " ic %0,0(%2)\n"
  193. " ic %1,0(%3)\n"
  194. " sr %0,%1\n"
  195. "1:"
  196. : "+d" (ret), "+d" (r0), "+a" (s1), "+a" (s2)
  197. : : "cc", "memory");
  198. return ret;
  199. }
  200. EXPORT_SYMBOL(strcmp);
  201. /**
  202. * strrchr - Find the last occurrence of a character in a string
  203. * @s: The string to be searched
  204. * @c: The character to search for
  205. */
  206. char *strrchr(const char *s, int c)
  207. {
  208. size_t len = __strend(s) - s;
  209. if (len)
  210. do {
  211. if (s[len] == (char) c)
  212. return (char *) s + len;
  213. } while (--len > 0);
  214. return NULL;
  215. }
  216. EXPORT_SYMBOL(strrchr);
  217. static inline int clcle(const char *s1, unsigned long l1,
  218. const char *s2, unsigned long l2)
  219. {
  220. register unsigned long r2 asm("2") = (unsigned long) s1;
  221. register unsigned long r3 asm("3") = (unsigned long) l1;
  222. register unsigned long r4 asm("4") = (unsigned long) s2;
  223. register unsigned long r5 asm("5") = (unsigned long) l2;
  224. int cc;
  225. asm volatile ("0: clcle %1,%3,0\n"
  226. " jo 0b\n"
  227. " ipm %0\n"
  228. " srl %0,28"
  229. : "=&d" (cc), "+a" (r2), "+a" (r3),
  230. "+a" (r4), "+a" (r5) : : "cc", "memory");
  231. return cc;
  232. }
  233. /**
  234. * strstr - Find the first substring in a %NUL terminated string
  235. * @s1: The string to be searched
  236. * @s2: The string to search for
  237. */
  238. char *strstr(const char *s1, const char *s2)
  239. {
  240. int l1, l2;
  241. l2 = __strend(s2) - s2;
  242. if (!l2)
  243. return (char *) s1;
  244. l1 = __strend(s1) - s1;
  245. while (l1-- >= l2) {
  246. int cc;
  247. cc = clcle(s1, l2, s2, l2);
  248. if (!cc)
  249. return (char *) s1;
  250. s1++;
  251. }
  252. return NULL;
  253. }
  254. EXPORT_SYMBOL(strstr);
  255. /**
  256. * memchr - Find a character in an area of memory.
  257. * @s: The memory area
  258. * @c: The byte to search for
  259. * @n: The size of the area.
  260. *
  261. * returns the address of the first occurrence of @c, or %NULL
  262. * if @c is not found
  263. */
  264. void *memchr(const void *s, int c, size_t n)
  265. {
  266. register int r0 asm("0") = (char) c;
  267. const void *ret = s + n;
  268. asm volatile ("0: srst %0,%1\n"
  269. " jo 0b\n"
  270. " jl 1f\n"
  271. " la %0,0\n"
  272. "1:"
  273. : "+a" (ret), "+&a" (s) : "d" (r0) : "cc", "memory");
  274. return (void *) ret;
  275. }
  276. EXPORT_SYMBOL(memchr);
  277. /**
  278. * memcmp - Compare two areas of memory
  279. * @s1: One area of memory
  280. * @s2: Another area of memory
  281. * @count: The size of the area.
  282. */
  283. int memcmp(const void *s1, const void *s2, size_t n)
  284. {
  285. int ret;
  286. ret = clcle(s1, n, s2, n);
  287. if (ret)
  288. ret = ret == 1 ? -1 : 1;
  289. return ret;
  290. }
  291. EXPORT_SYMBOL(memcmp);
  292. /**
  293. * memscan - Find a character in an area of memory.
  294. * @s: The memory area
  295. * @c: The byte to search for
  296. * @n: The size of the area.
  297. *
  298. * returns the address of the first occurrence of @c, or 1 byte past
  299. * the area if @c is not found
  300. */
  301. void *memscan(void *s, int c, size_t n)
  302. {
  303. register int r0 asm("0") = (char) c;
  304. const void *ret = s + n;
  305. asm volatile ("0: srst %0,%1\n"
  306. " jo 0b\n"
  307. : "+a" (ret), "+&a" (s) : "d" (r0) : "cc", "memory");
  308. return (void *) ret;
  309. }
  310. EXPORT_SYMBOL(memscan);