1 /* Copyright (c) 2007 Corinna Vinschen <corinna@vinschen.de> */
2 /*
3 FUNCTION
4 	<<stpcpy>>---copy string returning a pointer to its end
5 
6 INDEX
7 	stpcpy
8 
9 SYNOPSIS
10 	#include <string.h>
11 	char *stpcpy(char *restrict <[dst]>, const char *restrict <[src]>);
12 
13 DESCRIPTION
14 	<<stpcpy>> copies the string pointed to by <[src]>
15 	(including the terminating null character) to the array
16 	pointed to by <[dst]>.
17 
18 RETURNS
19 	This function returns a pointer to the end of the destination string,
20 	thus pointing to the trailing '\0'.
21 
22 PORTABILITY
23 <<stpcpy>> is a GNU extension, candidate for inclusion into POSIX/SUSv4.
24 
25 <<stpcpy>> requires no supporting OS subroutines.
26 
27 QUICKREF
28 	stpcpy gnu
29 */
30 
31 #define IN_STPCPY
32 #define _GNU_SOURCE
33 #include <string.h>
34 #include <limits.h>
35 #include <stdint.h>
36 
37 /*SUPPRESS 560*/
38 /*SUPPRESS 530*/
39 
40 /* Nonzero if either X or Y is not aligned on a "long" boundary.  */
41 #define UNALIGNED(X, Y) \
42   (((uintptr_t)X & (sizeof (long) - 1)) | ((uintptr_t)Y & (sizeof (long) - 1)))
43 
44 #if LONG_MAX == 2147483647L
45 #define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
46 #else
47 #if LONG_MAX == 9223372036854775807L
48 /* Nonzero if X (a long int) contains a NULL byte. */
49 #define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080)
50 #else
51 #error long int is not a 32bit or 64bit type.
52 #endif
53 #endif
54 
55 #ifndef DETECTNULL
56 #error long int is not a 32bit or 64bit byte
57 #endif
58 
59 char*
stpcpy(char * __restrict dst,const char * __restrict src)60 stpcpy (char *__restrict dst,
61 	const char *__restrict src)
62 {
63 #if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) && \
64     !defined(PICOLIBC_NO_OUT_OF_BOUNDS_READS)
65   long *aligned_dst;
66   const long *aligned_src;
67 
68   /* If SRC or DEST is unaligned, then copy bytes.  */
69   if (!UNALIGNED (src, dst))
70     {
71       aligned_dst = (long*)dst;
72       aligned_src = (long*)src;
73 
74       /* SRC and DEST are both "long int" aligned, try to do "long int"
75          sized copies.  */
76       while (!DETECTNULL(*aligned_src))
77         {
78           *aligned_dst++ = *aligned_src++;
79         }
80 
81       dst = (char*)aligned_dst;
82       src = (char*)aligned_src;
83     }
84 #endif /* not PREFER_SIZE_OVER_SPEED */
85 
86   while ((*dst++ = *src++))
87     ;
88   return --dst;
89 }
90