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 #include <string.h>
32 #include <limits.h>
33 #include <stdint.h>
34 
35 /*SUPPRESS 560*/
36 /*SUPPRESS 530*/
37 
38 /* Nonzero if either X or Y is not aligned on a "long" boundary.  */
39 #define UNALIGNED(X, Y) \
40   (((uintptr_t)X & (sizeof (long) - 1)) | ((uintptr_t)Y & (sizeof (long) - 1)))
41 
42 #if LONG_MAX == 2147483647L
43 #define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
44 #else
45 #if LONG_MAX == 9223372036854775807L
46 /* Nonzero if X (a long int) contains a NULL byte. */
47 #define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080)
48 #else
49 #error long int is not a 32bit or 64bit type.
50 #endif
51 #endif
52 
53 #ifndef DETECTNULL
54 #error long int is not a 32bit or 64bit byte
55 #endif
56 
57 char*
stpcpy(char * __restrict dst,const char * __restrict src)58 stpcpy (char *__restrict dst,
59 	const char *__restrict src)
60 {
61 #if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) && \
62     !defined(PICOLIBC_NO_OUT_OF_BOUNDS_READS)
63   long *aligned_dst;
64   const long *aligned_src;
65 
66   /* If SRC or DEST is unaligned, then copy bytes.  */
67   if (!UNALIGNED (src, dst))
68     {
69       aligned_dst = (long*)dst;
70       aligned_src = (long*)src;
71 
72       /* SRC and DEST are both "long int" aligned, try to do "long int"
73          sized copies.  */
74       while (!DETECTNULL(*aligned_src))
75         {
76           *aligned_dst++ = *aligned_src++;
77         }
78 
79       dst = (char*)aligned_dst;
80       src = (char*)aligned_src;
81     }
82 #endif /* not PREFER_SIZE_OVER_SPEED */
83 
84   while ((*dst++ = *src++))
85     ;
86   return --dst;
87 }
88