1 //! string implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/string.h.html 2 3 use core::{mem, ptr, slice, usize}; 4 use crate::unix::platform; 5 use cbitset::BitSet256; 6 use crate::unix::header::{errno::*, signal}; 7 use crate::unix::header::string::slice::memchr; 8 9 #[no_mangle] 10 pub unsafe extern "C" fn memccpy( 11 dest: *mut ::c_void, 12 src: *const ::c_void, 13 c: ::c_int, 14 n: ::size_t, 15 ) -> *mut ::c_void { 16 let to = memchr(src, c, n); 17 if to.is_null() { 18 return to; 19 } 20 let dist = (to as usize) - (src as usize); 21 if memcpy(dest, src, dist).is_null() { 22 return ptr::null_mut(); 23 } 24 (dest as *mut u8).add(dist + 1) as *mut ::c_void 25 } 26 27 #[no_mangle] 28 pub unsafe extern "C" fn memchr( 29 haystack: *const ::c_void, 30 needle: ::c_int, 31 len: ::size_t, 32 ) -> *mut ::c_void { 33 let haystack = slice::from_raw_parts(haystack as *const u8, len as usize); 34 35 match memchr::memchr(needle as u8, haystack) { 36 Some(index) => haystack[index..].as_ptr() as *mut ::c_void, 37 None => ptr::null_mut(), 38 } 39 } 40 41 #[no_mangle] 42 pub unsafe extern "C" fn memcmp(s1: *const ::c_void, s2: *const ::c_void, n: ::size_t) -> ::c_int { 43 let (div, rem) = (n / mem::size_of::<usize>(), n % mem::size_of::<usize>()); 44 let mut a = s1 as *const usize; 45 let mut b = s2 as *const usize; 46 for _ in 0..div { 47 if *a != *b { 48 for i in 0..mem::size_of::<usize>() { 49 let c = *(a as *const u8).add(i); 50 let d = *(b as *const u8).add(i); 51 if c != d { 52 return c as ::c_int - d as ::c_int; 53 } 54 } 55 unreachable!() 56 } 57 a = a.offset(1); 58 b = b.offset(1); 59 } 60 61 let mut a = a as *const u8; 62 let mut b = b as *const u8; 63 for _ in 0..rem { 64 if *a != *b { 65 return *a as ::c_int - *b as ::c_int; 66 } 67 a = a.offset(1); 68 b = b.offset(1); 69 } 70 0 71 } 72 73 #[no_mangle] 74 pub unsafe extern "C" fn memcpy(s1: *mut ::c_void, s2: *const ::c_void, n: ::size_t) -> *mut ::c_void { 75 let mut i = 0; 76 while i + 7 < n { 77 *(s1.add(i) as *mut u64) = *(s2.add(i) as *const u64); 78 i += 8; 79 } 80 while i < n { 81 *(s1 as *mut u8).add(i) = *(s2 as *const u8).add(i); 82 i += 1; 83 } 84 s1 85 } 86 87 #[no_mangle] 88 pub unsafe extern "C" fn memmove(s1: *mut ::c_void, s2: *const ::c_void, n: ::size_t) -> *mut ::c_void { 89 if s2 < s1 as *const ::c_void { 90 // copy from end 91 let mut i = n; 92 while i != 0 { 93 i -= 1; 94 *(s1 as *mut u8).add(i) = *(s2 as *const u8).add(i); 95 } 96 } else { 97 // copy from beginning 98 let mut i = 0; 99 while i < n { 100 *(s1 as *mut u8).add(i) = *(s2 as *const u8).add(i); 101 i += 1; 102 } 103 } 104 s1 105 } 106 107 #[no_mangle] 108 pub unsafe extern "C" fn memrchr( 109 haystack: *const ::c_void, 110 needle: ::c_int, 111 len: ::size_t, 112 ) -> *mut ::c_void { 113 let haystack = slice::from_raw_parts(haystack as *const u8, len as usize); 114 115 match memchr::memrchr(needle as u8, haystack) { 116 Some(index) => haystack[index..].as_ptr() as *mut ::c_void, 117 None => ptr::null_mut(), 118 } 119 } 120 121 #[no_mangle] 122 pub unsafe extern "C" fn memset(s: *mut ::c_void, c: ::c_int, n: ::size_t) -> *mut ::c_void { 123 for i in 0..n { 124 *(s as *mut u8).add(i) = c as u8; 125 } 126 s 127 } 128 129 #[no_mangle] 130 pub unsafe extern "C" fn strchr(mut s: *const ::c_char, c: ::c_int) -> *mut ::c_char { 131 let c = c as ::c_char; 132 while *s != 0 { 133 if *s == c { 134 return s as *mut ::c_char; 135 } 136 s = s.offset(1); 137 } 138 ptr::null_mut() 139 } 140 141 #[no_mangle] 142 pub unsafe extern "C" fn strcmp(s1: *const ::c_char, s2: *const ::c_char) -> ::c_int { 143 strncmp(s1, s2, usize::MAX) 144 } 145 146 #[no_mangle] 147 pub unsafe extern "C" fn strcoll(s1: *const ::c_char, s2: *const ::c_char) -> ::c_int { 148 // relibc has no locale stuff (yet) 149 strcmp(s1, s2) 150 } 151 152 #[no_mangle] 153 pub unsafe extern "C" fn strcpy(dst: *mut ::c_char, src: *const ::c_char) -> *mut ::c_char { 154 let mut i = 0; 155 156 loop { 157 let byte = *src.offset(i); 158 *dst.offset(i) = byte; 159 160 if byte == 0 { 161 break; 162 } 163 164 i += 1; 165 } 166 167 dst 168 } 169 170 pub unsafe fn inner_strspn(s1: *const ::c_char, s2: *const ::c_char, cmp: bool) -> ::size_t { 171 let mut s1 = s1 as *const u8; 172 let mut s2 = s2 as *const u8; 173 174 // The below logic is effectively ripped from the musl implementation. It 175 // works by placing each byte as it's own bit in an array of numbers. Each 176 // number can hold up to 8 * mem::size_of::<usize>() bits. We need 256 bits 177 // in total, to fit one byte. 178 179 let mut set = BitSet256::new(); 180 181 while *s2 != 0 { 182 set.insert(*s2 as usize); 183 s2 = s2.offset(1); 184 } 185 186 let mut i = 0; 187 while *s1 != 0 { 188 if set.contains(*s1 as usize) != cmp { 189 break; 190 } 191 i += 1; 192 s1 = s1.offset(1); 193 } 194 i 195 } 196 197 #[no_mangle] 198 pub unsafe extern "C" fn strcspn(s1: *const ::c_char, s2: *const ::c_char) -> ::size_t { 199 inner_strspn(s1, s2, false) 200 } 201 202 #[no_mangle] 203 pub unsafe extern "C" fn strdup(s1: *const ::c_char) -> *mut ::c_char { 204 strndup(s1, usize::MAX) 205 } 206 207 #[no_mangle] 208 pub unsafe extern "C" fn strndup(s1: *const ::c_char, size: ::size_t) -> *mut ::c_char { 209 let len = strnlen(s1, size); 210 211 // the "+ 1" is to account for the NUL byte 212 let buffer = platform::alloc(len + 1) as *mut ::c_char; 213 if buffer.is_null() { 214 platform::errno = ENOMEM as ::c_int; 215 } else { 216 //memcpy(buffer, s1, len) 217 for i in 0..len { 218 *buffer.add(i) = *s1.add(i); 219 } 220 *buffer.add(len) = 0; 221 } 222 223 buffer 224 } 225 226 #[no_mangle] 227 pub unsafe extern "C" fn strerror(errnum: ::c_int) -> *mut ::c_char { 228 use core::fmt::Write; 229 230 static mut strerror_buf: [u8; 256] = [0; 256]; 231 232 let mut w = platform::StringWriter(strerror_buf.as_mut_ptr(), strerror_buf.len()); 233 234 if errnum >= 0 && errnum < STR_ERROR.len() as ::c_int { 235 let _ = w.write_str(STR_ERROR[errnum as usize]); 236 } else { 237 let _ = w.write_fmt(format_args!("Unknown error {}", errnum)); 238 } 239 240 strerror_buf.as_mut_ptr() as *mut ::c_char 241 } 242 243 #[no_mangle] 244 pub unsafe extern "C" fn strerror_r(errnum: ::c_int, buf: *mut ::c_char, buflen: ::size_t) -> ::c_int { 245 let msg = strerror(errnum); 246 let len = strlen(msg); 247 248 if len >= buflen { 249 if buflen != 0 { 250 memcpy(buf as *mut ::c_void, msg as *const ::c_void, buflen - 1); 251 *buf.add(buflen - 1) = 0; 252 } 253 return ERANGE as ::c_int; 254 } 255 memcpy(buf as *mut ::c_void, msg as *const ::c_void, len + 1); 256 257 0 258 } 259 260 #[no_mangle] 261 pub unsafe extern "C" fn strlen(s: *const ::c_char) -> ::size_t { 262 strnlen(s, usize::MAX) 263 } 264 265 #[no_mangle] 266 pub unsafe extern "C" fn strnlen(s: *const ::c_char, size: ::size_t) -> ::size_t { 267 let mut i = 0; 268 while i < size { 269 if *s.add(i) == 0 { 270 break; 271 } 272 i += 1; 273 } 274 i as ::size_t 275 } 276 277 #[no_mangle] 278 pub unsafe extern "C" fn strnlen_s(s: *const ::c_char, size: ::size_t) -> ::size_t { 279 if s.is_null() { 280 0 281 } else { 282 strnlen(s, size) 283 } 284 } 285 286 #[no_mangle] 287 pub unsafe extern "C" fn strcat(s1: *mut ::c_char, s2: *const ::c_char) -> *mut ::c_char { 288 strncat(s1, s2, usize::MAX) 289 } 290 291 #[no_mangle] 292 pub unsafe extern "C" fn strncat(s1: *mut ::c_char, s2: *const ::c_char, n: ::size_t) -> *mut ::c_char { 293 let len = strlen(s1 as *const ::c_char); 294 let mut i = 0; 295 while i < n { 296 let b = *s2.add(i); 297 if b == 0 { 298 break; 299 } 300 301 *s1.add(len + i) = b; 302 i += 1; 303 } 304 *s1.add(len + i) = 0; 305 306 s1 307 } 308 309 #[no_mangle] 310 pub unsafe extern "C" fn strncmp(s1: *const ::c_char, s2: *const ::c_char, n: ::size_t) -> ::c_int { 311 let s1 = core::slice::from_raw_parts(s1 as *const ::c_uchar, n); 312 let s2 = core::slice::from_raw_parts(s2 as *const ::c_uchar, n); 313 314 for (&a, &b) in s1.iter().zip(s2.iter()) { 315 let val = (a as ::c_int) - (b as ::c_int); 316 if a != b || a == 0 { 317 return val; 318 } 319 } 320 321 0 322 } 323 324 #[no_mangle] 325 pub unsafe extern "C" fn strncpy(dst: *mut ::c_char, src: *const ::c_char, n: ::size_t) -> *mut ::c_char { 326 let mut i = 0; 327 328 while *src.add(i) != 0 && i < n { 329 *dst.add(i) = *src.add(i); 330 i += 1; 331 } 332 333 for i in i..n { 334 *dst.add(i) = 0; 335 } 336 337 dst 338 } 339 340 #[no_mangle] 341 pub unsafe extern "C" fn strpbrk(s1: *const ::c_char, s2: *const ::c_char) -> *mut ::c_char { 342 let p = s1.add(strcspn(s1, s2)); 343 if *p != 0 { 344 p as *mut ::c_char 345 } else { 346 ptr::null_mut() 347 } 348 } 349 350 #[no_mangle] 351 pub unsafe extern "C" fn strrchr(s: *const ::c_char, c: ::c_int) -> *mut ::c_char { 352 let len = strlen(s) as isize; 353 let c = c as i8; 354 let mut i = len - 1; 355 while i >= 0 { 356 if *s.offset(i) == c { 357 return s.offset(i) as *mut ::c_char; 358 } 359 i -= 1; 360 } 361 ptr::null_mut() 362 } 363 364 #[no_mangle] 365 pub unsafe extern "C" fn strsignal(sig: ::c_int) -> *const ::c_char { 366 signal::_signal_strings 367 .get(sig as usize) 368 .unwrap_or(&signal::_signal_strings[0]) // Unknown signal message 369 .as_ptr() as *const ::c_char 370 } 371 372 #[no_mangle] 373 pub unsafe extern "C" fn strspn(s1: *const ::c_char, s2: *const ::c_char) -> ::size_t { 374 inner_strspn(s1, s2, true) 375 } 376 377 unsafe fn inner_strstr( 378 mut haystack: *const ::c_char, 379 needle: *const ::c_char, 380 mask: ::c_char, 381 ) -> *mut ::c_char { 382 while *haystack != 0 { 383 let mut i = 0; 384 loop { 385 if *needle.offset(i) == 0 { 386 // We reached the end of the needle, everything matches this far 387 return haystack as *mut ::c_char; 388 } 389 if *haystack.offset(i) & mask != *needle.offset(i) & mask { 390 break; 391 } 392 393 i += 1; 394 } 395 396 haystack = haystack.offset(1); 397 } 398 ptr::null_mut() 399 } 400 401 #[no_mangle] 402 pub unsafe extern "C" fn strstr(haystack: *const ::c_char, needle: *const ::c_char) -> *mut ::c_char { 403 inner_strstr(haystack, needle, !0) 404 } 405 #[no_mangle] 406 pub unsafe extern "C" fn strcasestr(haystack: *const ::c_char, needle: *const ::c_char) -> *mut ::c_char { 407 inner_strstr(haystack, needle, !32) 408 } 409 410 #[no_mangle] 411 pub unsafe extern "C" fn strtok(s1: *mut ::c_char, delimiter: *const ::c_char) -> *mut ::c_char { 412 static mut HAYSTACK: *mut ::c_char = ptr::null_mut(); 413 strtok_r(s1, delimiter, &mut HAYSTACK) 414 } 415 416 #[no_mangle] 417 pub unsafe extern "C" fn strtok_r( 418 s: *mut ::c_char, 419 delimiter: *const ::c_char, 420 lasts: *mut *mut ::c_char, 421 ) -> *mut ::c_char { 422 // Loosely based on GLIBC implementation 423 let mut haystack = s; 424 if haystack.is_null() { 425 if (*lasts).is_null() { 426 return ptr::null_mut(); 427 } 428 haystack = *lasts; 429 } 430 431 // Skip past any extra delimiter left over from previous call 432 haystack = haystack.add(strspn(haystack, delimiter)); 433 if *haystack == 0 { 434 *lasts = ptr::null_mut(); 435 return ptr::null_mut(); 436 } 437 438 // Build token by injecting null byte into delimiter 439 let token = haystack; 440 haystack = strpbrk(token, delimiter); 441 if !haystack.is_null() { 442 haystack.write(0); 443 haystack = haystack.add(1); 444 *lasts = haystack; 445 } else { 446 *lasts = ptr::null_mut(); 447 } 448 449 token 450 } 451 452 #[no_mangle] 453 pub unsafe extern "C" fn strxfrm(s1: *mut ::c_char, s2: *const ::c_char, n: ::size_t) -> ::size_t { 454 // relibc has no locale stuff (yet) 455 let len = strlen(s2); 456 if len < n { 457 strcpy(s1, s2); 458 } 459 len 460 } 461 462 #[no_mangle] 463 pub unsafe extern "C" fn strlcpy(dst: *mut ::c_char, src: *const ::c_char, n: ::size_t) -> ::size_t { 464 let mut i = 0; 465 466 while *src.add(i) != 0 && i < n { 467 *dst.add(i) = *src.add(i); 468 i += 1; 469 } 470 471 *dst.add(i) = 0; 472 473 i as ::size_t 474 } 475 476 #[no_mangle] 477 pub unsafe extern "C" fn strlcat(dst: *mut ::c_char, src: *const ::c_char, n: ::size_t) -> ::size_t { 478 let len = strlen(dst) as isize; 479 let mut d = dst.offset(len); 480 481 strlcpy(d, src, n) 482 } 483