PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
strncpy.c
1/*
2 * strncpy.S -- strncmp function. On at least some MIPS chips, you get better
3 * code by hand unrolling the loops, and by using store words to zero the
4 * remainder of the buffer than the default newlib C version.
5 *
6 * Copyright (c) 2001 Red Hat, Inc.
7 *
8 * The authors hereby grant permission to use, copy, modify, distribute,
9 * and license this software and its documentation for any purpose, provided
10 * that existing copyright notices are retained in all copies and that this
11 * notice is included verbatim in any distributions. No written agreement,
12 * license, or royalty fee is required for any of the authorized uses.
13 * Modifications to this software may be copyrighted by their authors
14 * and need not follow the licensing terms described here, provided that
15 * the new terms are clearly indicated on the first page of each file where
16 * they apply. */
17
18#include <sysclib.h>
19#include <stddef.h>
20#include <stdint.h>
21
22#if !defined(__GNUC__) || (__GNUC__ < 3)
23#define __builtin_expect(a,b) a
24
25#else
26#ifdef __mips64
27/* Don't use limits test for the size of long, in order to allow the use of
28 64-bit stores on MIPS3 machines, even if -mlong32 was used. */
29typedef unsigned word_type __attribute__ ((mode (DI)));
30#else
31typedef unsigned word_type __attribute__ ((mode (SI)));
32#endif
33
34typedef unsigned si_type __attribute__ ((mode (SI)));
35typedef unsigned hi_type __attribute__ ((mode (HI)));
36
37#ifndef UNROLL_FACTOR
38#define UNROLL_FACTOR 4
39
40#elif (UNROLL_FACTOR != 2) && (UNROLL_FACTOR != 4)
41#error "UNROLL_FACTOR must be 2 or 4"
42#endif
43#endif
44
45char *
46strncpy (char *dst0, const char *src0, size_t count)
47{
48#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) || defined(__mips16) || !defined(__GNUC__) || (__GNUC__ < 3)
49 char *dst, *end;
50 const char *src;
51 int ch;
52
53 dst = dst0;
54 src = src0;
55 end = dst + count;
56 while (dst != end)
57 {
58 *dst++ = ch = *src++;
59 if (__builtin_expect (ch == '\0', 0))
60 {
61 while (dst != end)
62 *dst++ = '\0';
63
64 break;
65 }
66 }
67
68 return dst0;
69
70#else
71 unsigned char *dst;
72 unsigned char *dst_end;
73 unsigned char *end;
74 const unsigned char *src;
75 int ch0, ch1;
76#if UNROLL_FACTOR > 2
77 int ch2, ch3;
78#endif
79 int ch;
80 int odd_bytes;
81 size_t long_count;
82
83 dst = (unsigned char *)dst0;
84 src = (unsigned const char *)src0;
85 /* Take care of any odd bytes in the source data because we
86 * want to unroll where we read ahead 2 or 4 bytes at a time and then
87 * check each byte for the null terminator. This can result in
88 * a segfault for the case where the source pointer is unaligned,
89 * the null terminator is in valid memory, but reading 2 or 4 bytes at a
90 * time blindly eventually goes outside of valid memory. */
91 while (((uintptr_t) src & (UNROLL_FACTOR - 1)) != 0 && count > 0)
92 {
93 *dst++ = ch = *src++;
94 --count;
95 if (ch == '\0')
96 {
97 end = dst + count;
98 while (dst != end)
99 *dst++ = '\0';
100
101 return dst0;
102 }
103 }
104
105 if (__builtin_expect (count >= 4, 1))
106 {
107 odd_bytes = (count & (UNROLL_FACTOR - 1));
108 count -= odd_bytes;
109
110 do
111 {
112 ch0 = src[0];
113 ch1 = src[1];
114#if UNROLL_FACTOR > 2
115 ch2 = src[2];
116 ch3 = src[3];
117#endif
118 src += UNROLL_FACTOR;
119 count -= UNROLL_FACTOR;
120
121 dst[0] = ch0;
122 if (ch0 == '\0')
123 goto found_null0;
124
125 dst[1] = ch1;
126 if (ch1 == '\0')
127 goto found_null1;
128
129#if UNROLL_FACTOR > 2
130 dst[2] = ch2;
131 if (ch2 == '\0')
132 goto found_null2;
133
134 dst[3] = ch3;
135 if (ch3 == '\0')
136 goto found_null3;
137#endif
138
139 dst += UNROLL_FACTOR;
140 }
141 while (count);
142
143 /* fall through, count == 0, no null found, deal with last bytes */
144 count = odd_bytes;
145 }
146
147 end = dst + count;
148 while (dst != end)
149 {
150 *dst++ = ch = *src++;
151 if (ch == '\0')
152 {
153 while (dst != end)
154 *dst++ = '\0';
155
156 break;
157 }
158 }
159
160 return dst0;
161
162 /* Found null byte in first byte, count has been decremented by 4, null has
163 been stored in dst[0]. */
164 found_null0:
165 count++; /* add 1 to cover remaining byte */
166 dst -= 1; /* adjust dst += 4 gets correct ptr */
167 /* fall through */
168
169 /* Found null byte in second byte, count has been decremented by 4, null has
170 been stored in dst[1]. */
171 found_null1:
172#if UNROLL_FACTOR > 2
173 count++; /* add 1 to cover remaining byte */
174 dst -= 1; /* adjust dst += 4 gets correct ptr */
175 /* fall through */
176
177 /* Found null byte in third byte, count has been decremented by 4, null has
178 been stored in dst[2]. */
179 found_null2:
180 count++; /* add 1 to cover remaining byte */
181 dst -= 1; /* adjust dst += 4 gets correct ptr */
182 /* fall through */
183
184 /* Found null byte in fourth byte, count is accurate, dst has not been
185 updated yet. */
186 found_null3:
187#endif
188 count += odd_bytes; /* restore odd byte count */
189 dst += UNROLL_FACTOR;
190
191 /* Zero fill remainder of the array. Unroll the loop, and use word/dword
192 stores where we can. */
193 while (count && (((long)dst) & (sizeof (word_type) - 1)) != 0)
194 {
195 count--;
196 *dst++ = 0;
197 }
198
199 while (count >= UNROLL_FACTOR*sizeof (word_type))
200 {
201 count -= UNROLL_FACTOR*sizeof (word_type);
202 dst += UNROLL_FACTOR*sizeof (word_type);
203#if UNROLL_FACTOR > 2
204 ((word_type *)(void *)dst)[-4] = 0;
205 ((word_type *)(void *)dst)[-3] = 0;
206#endif
207 ((word_type *)(void *)dst)[-2] = 0;
208 ((word_type *)(void *)dst)[-1] = 0;
209 }
210
211#if UNROLL_FACTOR > 2
212 if (count >= 2*sizeof (word_type))
213 {
214 count -= 2*sizeof (word_type);
215 ((word_type *)(void *)dst)[0] = 0;
216 ((word_type *)(void *)dst)[1] = 0;
217 dst += 2*sizeof (word_type);
218 }
219#endif
220
221 if (count >= sizeof (word_type))
222 {
223 count -= sizeof (word_type);
224 ((word_type *)(void *)dst)[0] = 0;
225 dst += sizeof (word_type);
226 }
227
228#ifdef __mips64
229 if (count >= sizeof (si_type))
230 {
231 count -= sizeof (si_type);
232 ((si_type *)(void *)dst)[0] = 0;
233 dst += sizeof (si_type);
234 }
235#endif
236
237 if (count >= sizeof (hi_type))
238 {
239 count -= sizeof (hi_type);
240 ((hi_type *)(void *)dst)[0] = 0;
241 dst += sizeof (hi_type);
242 }
243
244 if (count)
245 *dst = '\0';
246
247 return dst0;
248#endif
249}
u32 count
start sector of fragmented bd/file