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