1 /*
2 Copyright (c) 1994 Cygnus Support.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms are permitted
6 provided that the above copyright notice and this paragraph are
7 duplicated in all such forms and that any documentation,
8 and/or other materials related to such
9 distribution and use acknowledge that the software was developed
10 at Cygnus Support, Inc. Cygnus Support, Inc. may not be used to
11 endorse or promote products derived from this software without
12 specific prior written permission.
13 THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17 /*
18 FUNCTION
19 <<strncat>>---concatenate strings
20
21 INDEX
22 strncat
23
24 SYNOPSIS
25 #include <string.h>
26 char *strncat(char *restrict <[dst]>, const char *restrict <[src]>,
27 size_t <[length]>);
28
29 DESCRIPTION
30 <<strncat>> appends not more than <[length]> characters from
31 the string pointed to by <[src]> (including the terminating
32 null character) to the end of the string pointed to by
33 <[dst]>. The initial character of <[src]> overwrites the null
34 character at the end of <[dst]>. A terminating null character
35 is always appended to the result
36
37 WARNINGS
38 Note that a null is always appended, so that if the copy is
39 limited by the <[length]> argument, the number of characters
40 appended to <[dst]> is <<n + 1>>.
41
42 RETURNS
43 This function returns the initial value of <[dst]>
44
45 PORTABILITY
46 <<strncat>> is ANSI C.
47
48 <<strncat>> requires no supporting OS subroutines.
49
50 QUICKREF
51 strncat ansi pure
52 */
53
54 #include <string.h>
55 #include <limits.h>
56 #include <stdint.h>
57
58 /* Nonzero if X is aligned on a "long" boundary. */
59 #define ALIGNED(X) \
60 (((uintptr_t)X & (sizeof (long) - 1)) == 0)
61
62 #if LONG_MAX == 2147483647L
63 #define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
64 #else
65 #if LONG_MAX == 9223372036854775807L
66 /* Nonzero if X (a long int) contains a NULL byte. */
67 #define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080)
68 #else
69 #error long int is not a 32bit or 64bit type.
70 #endif
71 #endif
72
73 #ifndef DETECTNULL
74 #error long int is not a 32bit or 64bit byte
75 #endif
76
77 #undef strncat
78
79 char *
strncat(char * __restrict s1,const char * __restrict s2,size_t n)80 strncat (char *__restrict s1,
81 const char *__restrict s2,
82 size_t n)
83 {
84 #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) || \
85 defined(PICOLIBC_NO_OUT_OF_BOUNDS_READS)
86 char *s = s1;
87
88 while (*s1)
89 s1++;
90 while (n-- != 0 && (*s1++ = *s2++))
91 {
92 if (n == 0)
93 *s1 = '\0';
94 }
95
96 return s;
97 #else
98 char *s = s1;
99
100 /* Skip over the data in s1 as quickly as possible. */
101 if (ALIGNED (s1))
102 {
103 unsigned long *aligned_s1 = (unsigned long *)s1;
104 while (!DETECTNULL (*aligned_s1))
105 aligned_s1++;
106
107 s1 = (char *)aligned_s1;
108 }
109
110 while (*s1)
111 s1++;
112
113 /* s1 now points to the its trailing null character, now copy
114 up to N bytes from S2 into S1 stopping if a NULL is encountered
115 in S2.
116
117 It is not safe to use strncpy here since it copies EXACTLY N
118 characters, NULL padding if necessary. */
119 while (n-- != 0 && (*s1++ = *s2++))
120 {
121 if (n == 0)
122 *s1 = '\0';
123 }
124
125 return s;
126 #endif /* not PREFER_SIZE_OVER_SPEED */
127 }
128