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 char *s = s1;
86
87 while (*s1)
88 s1++;
89 while (n-- != 0 && (*s1++ = *s2++))
90 {
91 if (n == 0)
92 *s1 = '\0';
93 }
94
95 return s;
96 #else
97 char *s = s1;
98
99 /* Skip over the data in s1 as quickly as possible. */
100 if (ALIGNED (s1))
101 {
102 unsigned long *aligned_s1 = (unsigned long *)s1;
103 while (!DETECTNULL (*aligned_s1))
104 aligned_s1++;
105
106 s1 = (char *)aligned_s1;
107 }
108
109 while (*s1)
110 s1++;
111
112 /* s1 now points to the its trailing null character, now copy
113 up to N bytes from S2 into S1 stopping if a NULL is encountered
114 in S2.
115
116 It is not safe to use strncpy here since it copies EXACTLY N
117 characters, NULL padding if necessary. */
118 while (n-- != 0 && (*s1++ = *s2++))
119 {
120 if (n == 0)
121 *s1 = '\0';
122 }
123
124 return s;
125 #endif /* not PREFER_SIZE_OVER_SPEED */
126 }
127