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