Files
glibc/string/stpcpy.c
T

122 lines
3.1 KiB
C
Raw Normal View History

/* Copyright (C) 1992-2023 Free Software Foundation, Inc.
1997-06-23 21:55:26 +00:00
This file is part of the GNU C Library.
1995-02-18 01:27:10 +00:00
1997-06-23 21:55:26 +00:00
The GNU C Library is free software; you can redistribute it and/or
2001-07-06 04:58:11 +00:00
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
1995-02-18 01:27:10 +00:00
1997-06-23 21:55:26 +00:00
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2001-07-06 04:58:11 +00:00
Lesser General Public License for more details.
1995-02-18 01:27:10 +00:00
2001-07-06 04:58:11 +00:00
You should have received a copy of the GNU Lesser General Public
2012-02-09 23:18:22 +00:00
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
1995-02-18 01:27:10 +00:00
2014-11-14 13:48:39 +00:00
#define NO_MEMPCPY_STPCPY_REDIRECT
1995-02-18 01:27:10 +00:00
#include <string.h>
2023-01-31 15:46:08 -03:00
#include <stdint.h>
#include <memcopy.h>
#include <string-fzb.h>
#include <string-misc.h>
1995-02-18 01:27:10 +00:00
1997-09-16 00:42:43 +00:00
#undef __stpcpy
#undef stpcpy
#ifndef STPCPY
# define STPCPY __stpcpy
1997-08-20 03:53:21 +00:00
#endif
2023-01-31 15:46:08 -03:00
static __always_inline char *
write_byte_from_word (op_t *dest, op_t word)
{
char *d = (char *) dest;
for (size_t i = 0; i < OPSIZ; i++, ++d)
{
char c = extractbyte (word, i);
*d = c;
if (c == '\0')
break;
}
return d;
}
static __always_inline char *
stpcpy_aligned_loop (op_t *restrict dst, const op_t *restrict src)
{
op_t word;
while (1)
{
word = *src++;
if (has_zero (word))
break;
*dst++ = word;
}
return write_byte_from_word (dst, word);
}
static __always_inline char *
stpcpy_unaligned_loop (op_t *restrict dst, const op_t *restrict src,
uintptr_t ofs)
{
op_t w2a = *src++;
uintptr_t sh_1 = ofs * CHAR_BIT;
uintptr_t sh_2 = OPSIZ * CHAR_BIT - sh_1;
op_t w2 = MERGE (w2a, sh_1, (op_t)-1, sh_2);
if (!has_zero (w2))
{
op_t w2b;
/* Unaligned loop. The invariant is that W2B, which is "ahead" of W1,
does not contain end-of-string. Therefore it is safe (and necessary)
to read another word from each while we do not have a difference. */
while (1)
{
w2b = *src++;
w2 = MERGE (w2a, sh_1, w2b, sh_2);
/* Check if there is zero on w2a. */
if (has_zero (w2))
goto out;
*dst++ = w2;
if (has_zero (w2b))
break;
w2a = w2b;
}
/* Align the final partial of P2. */
w2 = MERGE (w2b, sh_1, 0, sh_2);
}
out:
return write_byte_from_word (dst, w2);
}
1995-02-18 01:27:10 +00:00
/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */
char *
STPCPY (char *dest, const char *src)
1995-02-18 01:27:10 +00:00
{
2023-01-31 15:46:08 -03:00
/* Copy just a few bytes to make DEST aligned. */
size_t len = (-(uintptr_t) dest) % OPSIZ;
for (; len != 0; len--, ++dest)
{
char c = *src++;
*dest = c;
if (c == '\0')
return dest;
}
/* DEST is now aligned to op_t, SRC may or may not be. */
uintptr_t ofs = (uintptr_t) src % OPSIZ;
return ofs == 0 ? stpcpy_aligned_loop ((op_t*) dest, (const op_t *) src)
: stpcpy_unaligned_loop ((op_t*) dest,
(const op_t *) (src - ofs) , ofs);
1995-02-18 01:27:10 +00:00
}
weak_alias (__stpcpy, stpcpy)
libc_hidden_def (__stpcpy)
2004-05-28 06:56:51 +00:00
libc_hidden_builtin_def (stpcpy)