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

source code of glibc/string/stpcpy.c