string.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
  2. /*
  3. * string function definitions for NOLIBC
  4. * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
  5. */
  6. /* make sure to include all global symbols */
  7. #include "nolibc.h"
  8. #ifndef _NOLIBC_STRING_H
  9. #define _NOLIBC_STRING_H
  10. #include "arch.h"
  11. #include "std.h"
  12. static void *malloc(size_t len);
  13. /*
  14. * As much as possible, please keep functions alphabetically sorted.
  15. */
  16. static __attribute__((unused))
  17. int memcmp(const void *s1, const void *s2, size_t n)
  18. {
  19. size_t ofs = 0;
  20. int c1 = 0;
  21. while (ofs < n && !(c1 = ((unsigned char *)s1)[ofs] - ((unsigned char *)s2)[ofs])) {
  22. ofs++;
  23. }
  24. return c1;
  25. }
  26. #ifndef NOLIBC_ARCH_HAS_MEMMOVE
  27. /* might be ignored by the compiler without -ffreestanding, then found as
  28. * missing.
  29. */
  30. void *memmove(void *dst, const void *src, size_t len);
  31. __attribute__((weak,unused,section(".text.nolibc_memmove")))
  32. void *memmove(void *dst, const void *src, size_t len)
  33. {
  34. size_t dir, pos;
  35. pos = len;
  36. dir = -1;
  37. if (dst < src) {
  38. pos = -1;
  39. dir = 1;
  40. }
  41. while (len) {
  42. pos += dir;
  43. ((char *)dst)[pos] = ((const char *)src)[pos];
  44. len--;
  45. }
  46. return dst;
  47. }
  48. #endif /* #ifndef NOLIBC_ARCH_HAS_MEMMOVE */
  49. #ifndef NOLIBC_ARCH_HAS_MEMCPY
  50. /* must be exported, as it's used by libgcc on ARM */
  51. void *memcpy(void *dst, const void *src, size_t len);
  52. __attribute__((weak,unused,section(".text.nolibc_memcpy")))
  53. void *memcpy(void *dst, const void *src, size_t len)
  54. {
  55. size_t pos = 0;
  56. while (pos < len) {
  57. ((char *)dst)[pos] = ((const char *)src)[pos];
  58. pos++;
  59. }
  60. return dst;
  61. }
  62. #endif /* #ifndef NOLIBC_ARCH_HAS_MEMCPY */
  63. #ifndef NOLIBC_ARCH_HAS_MEMSET
  64. /* might be ignored by the compiler without -ffreestanding, then found as
  65. * missing.
  66. */
  67. void *memset(void *dst, int b, size_t len);
  68. __attribute__((weak,unused,section(".text.nolibc_memset")))
  69. void *memset(void *dst, int b, size_t len)
  70. {
  71. char *p = dst;
  72. while (len--) {
  73. /* prevent gcc from recognizing memset() here */
  74. __asm__ volatile("");
  75. *(p++) = b;
  76. }
  77. return dst;
  78. }
  79. #endif /* #ifndef NOLIBC_ARCH_HAS_MEMSET */
  80. #ifndef NOLIBC_ARCH_HAS_MEMCHR
  81. static __attribute__((unused))
  82. void *memchr(const void *s, int c, size_t len)
  83. {
  84. char *p = (char *)s;
  85. while (len--) {
  86. if (*p == (char)c)
  87. return p;
  88. p++;
  89. }
  90. return NULL;
  91. }
  92. #endif /* #ifndef NOLIBC_ARCH_HAS_MEMCHR */
  93. static __attribute__((unused))
  94. char *strchr(const char *s, int c)
  95. {
  96. while (*s) {
  97. if (*s == (char)c)
  98. return (char *)s;
  99. s++;
  100. }
  101. return NULL;
  102. }
  103. static __attribute__((unused))
  104. int strcmp(const char *a, const char *b)
  105. {
  106. unsigned int c;
  107. int diff;
  108. while (!(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c)
  109. ;
  110. return diff;
  111. }
  112. static __attribute__((unused))
  113. char *strcpy(char *dst, const char *src)
  114. {
  115. char *ret = dst;
  116. while ((*dst++ = *src++));
  117. return ret;
  118. }
  119. /* this function is only used with arguments that are not constants or when
  120. * it's not known because optimizations are disabled. Note that gcc 12
  121. * recognizes an strlen() pattern and replaces it with a jump to strlen(),
  122. * thus itself, hence the asm() statement below that's meant to disable this
  123. * confusing practice.
  124. */
  125. size_t strlen(const char *str);
  126. __attribute__((weak,unused,section(".text.nolibc_strlen")))
  127. size_t strlen(const char *str)
  128. {
  129. size_t len;
  130. for (len = 0; str[len]; len++)
  131. __asm__("");
  132. return len;
  133. }
  134. /* do not trust __builtin_constant_p() at -O0, as clang will emit a test and
  135. * the two branches, then will rely on an external definition of strlen().
  136. */
  137. #if defined(__OPTIMIZE__)
  138. #define nolibc_strlen(x) strlen(x)
  139. #define strlen(str) ({ \
  140. __builtin_constant_p((str)) ? \
  141. __builtin_strlen((str)) : \
  142. nolibc_strlen((str)); \
  143. })
  144. #endif
  145. static __attribute__((unused))
  146. size_t strnlen(const char *str, size_t maxlen)
  147. {
  148. size_t len;
  149. for (len = 0; (len < maxlen) && str[len]; len++);
  150. return len;
  151. }
  152. static __attribute__((unused))
  153. char *strdup(const char *str)
  154. {
  155. size_t len;
  156. char *ret;
  157. len = strlen(str);
  158. ret = malloc(len + 1);
  159. if (__builtin_expect(ret != NULL, 1))
  160. memcpy(ret, str, len + 1);
  161. return ret;
  162. }
  163. static __attribute__((unused))
  164. char *strndup(const char *str, size_t maxlen)
  165. {
  166. size_t len;
  167. char *ret;
  168. len = strnlen(str, maxlen);
  169. ret = malloc(len + 1);
  170. if (__builtin_expect(ret != NULL, 1)) {
  171. memcpy(ret, str, len);
  172. ret[len] = '\0';
  173. }
  174. return ret;
  175. }
  176. static __attribute__((unused))
  177. size_t strlcat(char *dst, const char *src, size_t size)
  178. {
  179. size_t len = strnlen(dst, size);
  180. /*
  181. * We want len < size-1. But as size is unsigned and can wrap
  182. * around, we use len + 1 instead.
  183. */
  184. while (len + 1 < size) {
  185. dst[len] = *src;
  186. if (*src == '\0')
  187. break;
  188. len++;
  189. src++;
  190. }
  191. if (len < size)
  192. dst[len] = '\0';
  193. while (*src++)
  194. len++;
  195. return len;
  196. }
  197. static __attribute__((unused))
  198. size_t strlcpy(char *dst, const char *src, size_t size)
  199. {
  200. size_t len;
  201. for (len = 0; len < size; len++) {
  202. dst[len] = src[len];
  203. if (!dst[len])
  204. return len;
  205. }
  206. if (size)
  207. dst[size-1] = '\0';
  208. while (src[len])
  209. len++;
  210. return len;
  211. }
  212. static __attribute__((unused))
  213. char *strncat(char *dst, const char *src, size_t size)
  214. {
  215. char *orig = dst;
  216. while (*dst)
  217. dst++;
  218. while (size && (*dst = *src)) {
  219. src++;
  220. dst++;
  221. size--;
  222. }
  223. *dst = 0;
  224. return orig;
  225. }
  226. static __attribute__((unused))
  227. int strncmp(const char *a, const char *b, size_t size)
  228. {
  229. unsigned int c;
  230. int diff = 0;
  231. while (size-- &&
  232. !(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c)
  233. ;
  234. return diff;
  235. }
  236. static __attribute__((unused))
  237. char *strncpy(char *dst, const char *src, size_t size)
  238. {
  239. size_t len;
  240. for (len = 0; len < size; len++)
  241. if ((dst[len] = *src))
  242. src++;
  243. return dst;
  244. }
  245. static __attribute__((unused))
  246. char *strrchr(const char *s, int c)
  247. {
  248. const char *ret = NULL;
  249. while (*s) {
  250. if (*s == (char)c)
  251. ret = s;
  252. s++;
  253. }
  254. return (char *)ret;
  255. }
  256. static __attribute__((unused))
  257. char *strstr(const char *haystack, const char *needle)
  258. {
  259. size_t len_haystack, len_needle;
  260. len_needle = strlen(needle);
  261. if (!len_needle)
  262. return NULL;
  263. len_haystack = strlen(haystack);
  264. while (len_haystack >= len_needle) {
  265. if (!memcmp(haystack, needle, len_needle))
  266. return (char *)haystack;
  267. haystack++;
  268. len_haystack--;
  269. }
  270. return NULL;
  271. }
  272. static __attribute__((unused))
  273. int tolower(int c)
  274. {
  275. if (c >= 'A' && c <= 'Z')
  276. return c - 'A' + 'a';
  277. return c;
  278. }
  279. static __attribute__((unused))
  280. int toupper(int c)
  281. {
  282. if (c >= 'a' && c <= 'z')
  283. return c - 'a' + 'A';
  284. return c;
  285. }
  286. #endif /* _NOLIBC_STRING_H */