stpcpy.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /* Copyright (C) 1992-2026 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. The GNU C Library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. The GNU C Library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with the GNU C Library; if not, see
  13. <https://www.gnu.org/licenses/>. */
  14. #define NO_MEMPCPY_STPCPY_REDIRECT
  15. #include <string.h>
  16. #include <stdint.h>
  17. #include <memcopy.h>
  18. #include <string-fzb.h>
  19. #include <string-misc.h>
  20. #undef __stpcpy
  21. #undef stpcpy
  22. #ifndef STPCPY
  23. # define STPCPY __stpcpy
  24. #endif
  25. static __always_inline char *
  26. write_byte_from_word (op_t *dest, op_t word)
  27. {
  28. char *d = (char *) dest;
  29. for (size_t i = 0; i < OPSIZ; i++, ++d)
  30. {
  31. char c = extractbyte (word, i);
  32. *d = c;
  33. if (c == '\0')
  34. break;
  35. }
  36. return d;
  37. }
  38. static __always_inline char *
  39. stpcpy_aligned_loop (op_t *restrict dst, const op_t *restrict src)
  40. {
  41. op_t word;
  42. while (1)
  43. {
  44. word = *src++;
  45. if (has_zero (word))
  46. break;
  47. *dst++ = word;
  48. }
  49. return write_byte_from_word (dst, word);
  50. }
  51. static __always_inline char *
  52. stpcpy_unaligned_loop (op_t *restrict dst, const op_t *restrict src,
  53. uintptr_t ofs)
  54. {
  55. op_t w2a = *src++;
  56. uintptr_t sh_1 = ofs * CHAR_BIT;
  57. uintptr_t sh_2 = OPSIZ * CHAR_BIT - sh_1;
  58. op_t w2 = MERGE (w2a, sh_1, (op_t)-1, sh_2);
  59. if (!has_zero (w2))
  60. {
  61. op_t w2b;
  62. /* Unaligned loop. The invariant is that W2B, which is "ahead" of W1,
  63. does not contain end-of-string. Therefore it is safe (and necessary)
  64. to read another word from each while we do not have a difference. */
  65. while (1)
  66. {
  67. w2b = *src++;
  68. w2 = MERGE (w2a, sh_1, w2b, sh_2);
  69. /* Check if there is zero on w2a. */
  70. if (has_zero (w2))
  71. goto out;
  72. *dst++ = w2;
  73. if (has_zero (w2b))
  74. break;
  75. w2a = w2b;
  76. }
  77. /* Align the final partial of P2. */
  78. w2 = MERGE (w2b, sh_1, 0, sh_2);
  79. }
  80. out:
  81. return write_byte_from_word (dst, w2);
  82. }
  83. /* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */
  84. char *
  85. STPCPY (char *dest, const char *src)
  86. {
  87. /* Copy just a few bytes to make DEST aligned. */
  88. size_t len = (-(uintptr_t) dest) % OPSIZ;
  89. for (; len != 0; len--, ++dest)
  90. {
  91. char c = *src++;
  92. *dest = c;
  93. if (c == '\0')
  94. return dest;
  95. }
  96. /* DEST is now aligned to op_t, SRC may or may not be. */
  97. uintptr_t ofs = (uintptr_t) src % OPSIZ;
  98. return ofs == 0 ? stpcpy_aligned_loop ((op_t*) dest, (const op_t *) src)
  99. : stpcpy_unaligned_loop ((op_t*) dest,
  100. (const op_t *) (src - ofs) , ofs);
  101. }
  102. weak_alias (__stpcpy, stpcpy)
  103. libc_hidden_def (__stpcpy)
  104. libc_hidden_builtin_def (stpcpy)