/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
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.
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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
. */
#include
#include
#include
#include
#include
#include
#include
#undef strcpy
#ifndef STRCPY
# define STRCPY strcpy
#endif
/* Copy SRC to DEST. */
char *
STRCPY (char *dest, const char *src)
{
char *dst = dest;
const op_t *xs;
op_t *xd;
op_t ws;
#if _STRING_ARCH_unaligned
/* For architectures which supports unaligned memory operations, it first
aligns the source pointer, reads op_t bytes at time until a zero is
found, and writes unaligned to destination. */
uintptr_t n = -(uintptr_t) src % sizeof (op_t);
for (uintptr_t i = 0; i < n; ++i)
{
unsigned c = *src++;
*dst++ = c;
if (c == '\0')
return dest;
}
xs = (const op_t *) src;
ws = *xs++;
xd = (op_t *) dst;
while (!has_zero (ws))
{
*xd++ = ws;
ws = *xs++;
}
#else
/* For architectures which only supports aligned accesses, it first align
the destination pointer. */
uintptr_t n = -(uintptr_t) dst % sizeof (op_t);
for (uintptr_t i = 0; i < n; ++i)
{
unsigned c = *src++;
*dst++ = c;
if (c == '\0')
return dest;
}
xd = (op_t *) dst;
/* Destination is aligned to op_t while source might be not. */
uintptr_t ofs = (uintptr_t) src % sizeof (op_t);
if (ofs == 0)
{
/* Aligned loop. If a zero is found, exit to copy the remaining
bytes. */
xs = (const op_t *) src;
ws = *xs++;
while (!has_zero (ws))
{
*xd++ = ws;
ws = *xs++;
}
}
else
{
/* Unaligned loop: align the source pointer and mask off the
undesirable bytes which is not part of the string. */
op_t wsa, wsb;
uintptr_t sh_1, sh_2;
xs = (const op_t *)(src - ofs);
wsa = *xs++;
sh_1 = ofs * CHAR_BIT;
sh_2 = sizeof(op_t) * CHAR_BIT - sh_1;
/* Align the first partial op_t from source, with 0xff for the rest
of the bytes so that we can also apply the has_zero test to see if we
have already reached EOS. If we have, then we can simply fall
through to the final byte copies. */
ws = MERGE (wsa, sh_1, (op_t)-1, sh_2);
if (!has_zero (ws))
{
while (1)
{
wsb = *xs++;
ws = MERGE (wsa, sh_1, wsb, sh_2);
if (has_zero (wsb))
break;
*xd++ = ws;
wsa = wsb;
}
/* WS may contain bytes that we not written yet in destination.
Write them down and merge with the op_t containing the EOS
byte. */
if (!has_zero (ws))
{
*xd++ = ws;
ws = MERGE (wsb, sh_1, ws, sh_2);
}
}
}
#endif
/* Just copy the final bytes from op_t. */
dst = (char *) xd;
uintptr_t fz = index_first_zero (ws);
for (uintptr_t i = 0; i < fz + 1; i++)
*dst++ = extractbyte (ws, i);
return dest;
}
libc_hidden_builtin_def (strcpy)