1 //! wchar implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/wchar.h.html 2 3 use core::{char, ffi::VaList as va_list, mem, ptr, slice, usize}; 4 use crate::unix::platform; 5 use crate::unix::header::{ 6 ctype::isspace, errno::ERANGE, stdio::*, stdlib::MB_CUR_MAX, string, time::*, wctype::*, 7 }; 8 9 mod utf8; 10 #[repr(C)] 11 #[derive(Clone, Copy)] 12 pub struct mbstate_t; 13 14 #[no_mangle] 15 pub unsafe extern "C" fn btowc(c: ::c_int) -> ::wint_t { 16 //Check for EOF 17 if c == EOF { 18 return WEOF; 19 } 20 21 let uc = c as u8; 22 let c = uc as ::c_char; 23 let mut ps: mbstate_t = mbstate_t; 24 let mut wc: ::wchar_t = 0; 25 let saved_errno = platform::errno; 26 let status = mbrtowc(&mut wc, &c as *const ::c_char, 1, &mut ps); 27 if status == usize::max_value() || status == usize::max_value() - 1 { 28 platform::errno = saved_errno; 29 return WEOF; 30 } 31 wc as ::wint_t 32 } 33 34 #[no_mangle] 35 pub unsafe extern "C" fn fgetwc(stream: *mut FILE) -> ::wint_t { 36 //TODO: Real multibyte 37 btowc(fgetc(stream)) 38 } 39 40 #[no_mangle] 41 pub unsafe extern "C" fn fgetws(ws: *mut ::wchar_t, n: ::c_int, stream: *mut FILE) -> *mut ::wchar_t { 42 //TODO: lock 43 let mut i = 0; 44 while ((i + 1) as ::c_int) < n { 45 let wc = fgetwc(stream); 46 if wc == WEOF { 47 return ptr::null_mut(); 48 } 49 *ws.add(i) = wc as ::wchar_t; 50 i += 1; 51 } 52 while (i as ::c_int) < n { 53 *ws.add(i) = 0; 54 i += 1; 55 } 56 ws 57 } 58 59 #[no_mangle] 60 pub unsafe extern "C" fn fputwc(wc: ::wchar_t, stream: *mut FILE) -> ::wint_t { 61 //Convert ::wchar_t to multibytes first 62 static mut INTERNAL: mbstate_t = mbstate_t; 63 let mut bytes: [::c_char; MB_CUR_MAX as usize] = [0; MB_CUR_MAX as usize]; 64 65 let amount = wcrtomb(bytes.as_mut_ptr(), wc, &mut INTERNAL); 66 67 for i in 0..amount { 68 fputc(bytes[i] as ::c_int, &mut *stream); 69 } 70 71 wc as ::wint_t 72 } 73 74 #[no_mangle] 75 pub unsafe extern "C" fn fputws(ws: *const ::wchar_t, stream: *mut FILE) -> ::c_int { 76 let mut i = 0; 77 loop { 78 let wc = *ws.add(i); 79 if wc == 0 { 80 return 0; 81 } 82 if fputwc(wc, stream) == WEOF { 83 return -1; 84 } 85 i += 1; 86 } 87 } 88 89 #[no_mangle] 90 pub unsafe extern "C" fn fwide(stream: *mut FILE, mode: ::c_int) -> ::c_int { 91 (*stream).try_set_orientation(mode) 92 } 93 94 #[no_mangle] 95 pub unsafe extern "C" fn getwc(stream: *mut FILE) -> ::wint_t { 96 fgetwc(stream) 97 } 98 99 #[no_mangle] 100 pub unsafe extern "C" fn getwchar() -> ::wint_t { 101 fgetwc(stdin) 102 } 103 104 #[no_mangle] 105 pub unsafe extern "C" fn mbsinit(ps: *const mbstate_t) -> ::c_int { 106 //Add a check for the state maybe 107 if ps.is_null() { 108 1 109 } else { 110 0 111 } 112 } 113 114 #[no_mangle] 115 pub unsafe extern "C" fn mbrlen(s: *const ::c_char, n: ::size_t, _ps: *mut mbstate_t) -> ::size_t { 116 static mut INTERNAL: mbstate_t = mbstate_t; 117 mbrtowc(ptr::null_mut(), s, n, &mut INTERNAL) 118 } 119 120 //Only works for UTF8 at the moment 121 #[no_mangle] 122 pub unsafe extern "C" fn mbrtowc( 123 pwc: *mut ::wchar_t, 124 s: *const ::c_char, 125 n: ::size_t, 126 ps: *mut mbstate_t, 127 ) -> ::size_t { 128 static mut INTERNAL: mbstate_t = mbstate_t; 129 130 if ps.is_null() { 131 let _ps = &mut INTERNAL; 132 } 133 if s.is_null() { 134 let xs: [::c_char; 1] = [0]; 135 utf8::mbrtowc(pwc, &xs[0] as *const ::c_char, 1, ps) 136 } else { 137 utf8::mbrtowc(pwc, s, n, ps) 138 } 139 } 140 141 //Convert a multibyte string to a wide string with a limited amount of bytes 142 //Required for in POSIX.1-2008 143 #[no_mangle] 144 pub unsafe extern "C" fn mbsnrtowcs( 145 dst_ptr: *mut ::wchar_t, 146 src_ptr: *mut *const ::c_char, 147 src_len: ::size_t, 148 dst_len: ::size_t, 149 ps: *mut mbstate_t, 150 ) -> ::size_t { 151 static mut INTERNAL: mbstate_t = mbstate_t; 152 153 if ps.is_null() { 154 let _ps = &mut INTERNAL; 155 } 156 157 let mut src = *src_ptr; 158 159 let mut dst_offset: usize = 0; 160 let mut src_offset: usize = 0; 161 162 while (dst_ptr.is_null() || dst_offset < dst_len) && src_offset < src_len { 163 let ps_copy = *ps; 164 let mut wc: ::wchar_t = 0; 165 let amount = mbrtowc(&mut wc, src.add(src_offset), src_len - src_offset, ps); 166 167 // Stop in the event a decoding error occured. 168 if amount == -1isize as usize { 169 *src_ptr = src.add(src_offset); 170 return 1isize as usize; 171 } 172 173 // Stop decoding early in the event we encountered a partial character. 174 if amount == -2isize as usize { 175 *ps = ps_copy; 176 break; 177 } 178 179 // Store the decoded wide character in the destination buffer. 180 if !dst_ptr.is_null() { 181 *dst_ptr.add(dst_offset) = wc; 182 } 183 184 // Stop decoding after decoding a null character and return a NULL 185 // source pointer to the caller, not including the null character in the 186 // number of characters stored in the destination buffer. 187 if wc == 0 { 188 src = ptr::null(); 189 src_offset = 0; 190 break; 191 } 192 193 dst_offset += 1; 194 src_offset += amount; 195 } 196 197 *src_ptr = src.add(src_offset); 198 dst_offset 199 } 200 201 //Convert a multibyte string to a wide string 202 #[no_mangle] 203 pub unsafe extern "C" fn mbsrtowcs( 204 dst: *mut ::wchar_t, 205 src: *mut *const ::c_char, 206 len: ::size_t, 207 ps: *mut mbstate_t, 208 ) -> ::size_t { 209 mbsnrtowcs(dst, src, ::size_t::max_value(), len, ps) 210 } 211 212 #[no_mangle] 213 pub unsafe extern "C" fn putwc(wc: ::wchar_t, stream: *mut FILE) -> ::wint_t { 214 fputwc(wc, &mut *stream) 215 } 216 217 #[no_mangle] 218 pub unsafe extern "C" fn putwchar(wc: ::wchar_t) -> ::wint_t { 219 fputwc(wc, &mut *stdout) 220 } 221 222 // #[no_mangle] 223 pub extern "C" fn swprintf( 224 _s: *mut ::wchar_t, 225 _n: ::size_t, 226 _format: *const ::wchar_t, 227 _ap: va_list, 228 ) -> ::c_int { 229 unimplemented!(); 230 } 231 232 // #[no_mangle] 233 pub extern "C" fn swscanf(_s: *const ::wchar_t, _format: *const ::wchar_t, _ap: va_list) -> ::c_int { 234 unimplemented!(); 235 } 236 237 // #[no_mangle] 238 pub extern "C" fn ungetwc(_wc: ::wint_t, _stream: *mut FILE) -> ::wint_t { 239 unimplemented!(); 240 } 241 242 // #[no_mangle] 243 pub extern "C" fn vfwprintf(_stream: *mut FILE, _format: *const ::wchar_t, _arg: va_list) -> ::c_int { 244 unimplemented!(); 245 } 246 247 // #[no_mangle] 248 pub extern "C" fn vwprintf(_format: *const ::wchar_t, _arg: va_list) -> ::c_int { 249 unimplemented!(); 250 } 251 252 // #[no_mangle] 253 pub extern "C" fn vswprintf( 254 _s: *mut ::wchar_t, 255 _n: ::size_t, 256 _format: *const ::wchar_t, 257 _arg: va_list, 258 ) -> ::c_int { 259 unimplemented!(); 260 } 261 262 //widechar to multibyte 263 #[no_mangle] 264 pub unsafe extern "C" fn wcrtomb(s: *mut ::c_char, wc: ::wchar_t, ps: *mut mbstate_t) -> ::size_t { 265 let mut buffer: [::c_char; MB_CUR_MAX as usize] = [0; MB_CUR_MAX as usize]; 266 let (s_cpy, wc_cpy) = if s.is_null() { 267 (buffer.as_mut_ptr(), 0) 268 } else { 269 (s, wc) 270 }; 271 272 utf8::wcrtomb(s_cpy, wc_cpy, ps) 273 } 274 275 #[no_mangle] 276 pub unsafe extern "C" fn wcscat(ws1: *mut ::wchar_t, ws2: *const ::wchar_t) -> *mut ::wchar_t { 277 wcsncat(ws1, ws2, usize::MAX) 278 } 279 280 #[no_mangle] 281 pub unsafe extern "C" fn wcschr(ws: *const ::wchar_t, wc: ::wchar_t) -> *mut ::wchar_t { 282 let mut i = 0; 283 loop { 284 if *ws.add(i) == wc { 285 return ws.add(i) as *mut ::wchar_t; 286 } else if *ws.add(i) == 0 { 287 return ptr::null_mut(); 288 } 289 i += 1; 290 } 291 } 292 293 #[no_mangle] 294 pub unsafe extern "C" fn wcscmp(ws1: *const ::wchar_t, ws2: *const ::wchar_t) -> ::c_int { 295 wcsncmp(ws1, ws2, usize::MAX) 296 } 297 298 #[no_mangle] 299 pub unsafe extern "C" fn wcscoll(ws1: *const ::wchar_t, ws2: *const ::wchar_t) -> ::c_int { 300 //TODO: locale comparison 301 wcscmp(ws1, ws2) 302 } 303 304 #[no_mangle] 305 pub unsafe extern "C" fn wcscpy(ws1: *mut ::wchar_t, ws2: *const ::wchar_t) -> *mut ::wchar_t { 306 let mut i = 0; 307 loop { 308 let wc = *ws2.add(i); 309 *ws1.add(i) = wc; 310 i += 1; 311 if wc == 0 { 312 return ws1; 313 } 314 } 315 } 316 317 unsafe fn inner_wcsspn(mut wcs: *const ::wchar_t, set: *const ::wchar_t, reject: bool) -> ::size_t { 318 let mut count = 0; 319 while (*wcs) != 0 && wcschr(set, *wcs).is_null() == reject { 320 wcs = wcs.add(1); 321 count += 1; 322 } 323 count 324 } 325 326 #[no_mangle] 327 pub unsafe extern "C" fn wcscspn(wcs: *const ::wchar_t, set: *const ::wchar_t) -> ::size_t { 328 inner_wcsspn(wcs, set, true) 329 } 330 331 // #[no_mangle] 332 pub extern "C" fn wcsftime( 333 _wcs: *mut ::wchar_t, 334 _maxsize: ::size_t, 335 _format: *const ::wchar_t, 336 _timptr: *mut tm, 337 ) -> ::size_t { 338 unimplemented!(); 339 } 340 341 #[no_mangle] 342 pub unsafe extern "C" fn wcslen(ws: *const ::wchar_t) -> ::size_t { 343 let mut i = 0; 344 loop { 345 if *ws.add(i) == 0 { 346 return i; 347 } 348 i += 1; 349 } 350 } 351 352 #[no_mangle] 353 pub unsafe extern "C" fn wcsncat( 354 ws1: *mut ::wchar_t, 355 ws2: *const ::wchar_t, 356 n: ::size_t, 357 ) -> *mut ::wchar_t { 358 let len = wcslen(ws1); 359 let dest = ws1.add(len); 360 let mut i = 0; 361 while i < n { 362 let wc = *ws2.add(i); 363 if wc == 0 { 364 break; 365 } 366 *dest.add(i) = wc; 367 i += 1; 368 } 369 *dest.add(i) = 0; 370 ws1 371 } 372 373 #[no_mangle] 374 pub unsafe extern "C" fn wcsncmp(ws1: *const ::wchar_t, ws2: *const ::wchar_t, n: ::size_t) -> ::c_int { 375 for i in 0..n { 376 let wc1 = *ws1.add(i); 377 let wc2 = *ws2.add(i); 378 if wc1 != wc2 { 379 return wc1 - wc2; 380 } else if wc1 == 0 { 381 break; 382 } 383 } 384 0 385 } 386 387 #[no_mangle] 388 pub unsafe extern "C" fn wcsncpy( 389 ws1: *mut ::wchar_t, 390 ws2: *const ::wchar_t, 391 n: ::size_t, 392 ) -> *mut ::wchar_t { 393 let mut i = 0; 394 while i < n { 395 let wc = *ws2.add(i); 396 *ws1.add(i) = wc; 397 i += 1; 398 if wc == 0 { 399 break; 400 } 401 } 402 while i < n { 403 *ws1.add(i) = 0; 404 i += 1; 405 } 406 ws1 407 } 408 409 #[no_mangle] 410 pub unsafe extern "C" fn wcspbrk(mut wcs: *const ::wchar_t, set: *const ::wchar_t) -> *mut ::wchar_t { 411 wcs = wcs.add(wcscspn(wcs, set)); 412 if *wcs == 0 { 413 ptr::null_mut() 414 } else { 415 // Once again, C wants us to transmute a const pointer to a 416 // mutable one... 417 wcs as *mut _ 418 } 419 } 420 421 #[no_mangle] 422 pub unsafe extern "C" fn wcsrchr(ws1: *const ::wchar_t, wc: ::wchar_t) -> *mut ::wchar_t { 423 let mut last_matching_wc = 0 as *const ::wchar_t; 424 let mut i = 0; 425 426 while *ws1.add(i) != 0 { 427 if *ws1.add(i) == wc { 428 last_matching_wc = ws1.add(i); 429 } 430 i += 1; 431 } 432 433 last_matching_wc as *mut ::wchar_t 434 } 435 436 // #[no_mangle] 437 pub extern "C" fn wcsrtombs( 438 _dst: *mut ::c_char, 439 _src: *mut *const ::wchar_t, 440 _len: ::size_t, 441 _ps: *mut mbstate_t, 442 ) -> ::size_t { 443 unimplemented!(); 444 } 445 446 #[no_mangle] 447 pub unsafe extern "C" fn wcsspn(wcs: *const ::wchar_t, set: *const ::wchar_t) -> ::size_t { 448 inner_wcsspn(wcs, set, false) 449 } 450 451 #[no_mangle] 452 pub unsafe extern "C" fn wcsstr(ws1: *const ::wchar_t, ws2: *const ::wchar_t) -> *mut ::wchar_t { 453 // Get length of ws2, not including null terminator 454 let ws2_len = wcslen(ws2); 455 456 // The standard says that we must return ws1 if ws2 has length 0 457 if ws2_len == 0 { 458 ws1 as *mut ::wchar_t 459 } else { 460 let ws1_len = wcslen(ws1); 461 462 // Construct slices without null terminator 463 let ws1_slice = slice::from_raw_parts(ws1, ws1_len); 464 let ws2_slice = slice::from_raw_parts(ws2, ws2_len); 465 466 /* Sliding ws2-sized window iterator on ws1. The iterator 467 * returns None if ws2 is longer than ws1. */ 468 let mut ws1_windows = ws1_slice.windows(ws2_len); 469 470 /* Find the first offset into ws1 where the window is equal to 471 * the ws2 contents. Return null pointer if no match is found. */ 472 match ws1_windows.position(|ws1_window| ws1_window == ws2_slice) { 473 Some(pos) => ws1.add(pos) as *mut ::wchar_t, 474 None => ptr::null_mut(), 475 } 476 } 477 } 478 479 macro_rules! skipws { 480 ($ptr:expr) => { 481 while isspace(*$ptr) != 0 { 482 $ptr = $ptr.add(1); 483 } 484 }; 485 } 486 487 #[no_mangle] 488 pub unsafe extern "C" fn wcstod(mut ptr: *const ::wchar_t, end: *mut *mut ::wchar_t) -> ::c_double { 489 const RADIX: u32 = 10; 490 491 skipws!(ptr); 492 let negative = *ptr == '-' as ::wchar_t; 493 if negative { 494 ptr = ptr.add(1); 495 } 496 497 let mut result: ::c_double = 0.0; 498 while let Some(digit) = char::from_u32(*ptr as _).and_then(|c| c.to_digit(RADIX)) { 499 result *= 10.0; 500 if negative { 501 result -= digit as ::c_double; 502 } else { 503 result += digit as ::c_double; 504 } 505 ptr = ptr.add(1); 506 } 507 if *ptr == '.' as ::wchar_t { 508 ptr = ptr.add(1); 509 510 let mut scale = 1.0; 511 while let Some(digit) = char::from_u32(*ptr as _).and_then(|c| c.to_digit(RADIX)) { 512 scale /= 10.0; 513 if negative { 514 result -= digit as ::c_double * scale; 515 } else { 516 result += digit as ::c_double * scale; 517 } 518 ptr = ptr.add(1); 519 } 520 } 521 if !end.is_null() { 522 *end = ptr as *mut _; 523 } 524 result 525 } 526 527 #[no_mangle] 528 pub unsafe extern "C" fn wcstok( 529 mut wcs: *mut ::wchar_t, 530 delim: *const ::wchar_t, 531 state: *mut *mut ::wchar_t, 532 ) -> *mut ::wchar_t { 533 // Choose starting position 534 if wcs.is_null() { 535 if (*state).is_null() { 536 // There was no next token 537 return ptr::null_mut(); 538 } 539 wcs = *state; 540 } 541 542 // Advance past any delimiters 543 wcs = wcs.add(wcsspn(wcs, delim)); 544 545 // Check end 546 if *wcs == 0 { 547 *state = ptr::null_mut(); 548 return ptr::null_mut(); 549 } 550 551 // Advance *to* any delimiters 552 let end = wcspbrk(wcs, delim); 553 if end.is_null() { 554 *state = ptr::null_mut(); 555 } else { 556 *end = 0; 557 *state = end.add(1); 558 } 559 wcs 560 } 561 562 macro_rules! strtou_impl { 563 ($type:ident, $ptr:expr, $base:expr) => { 564 strtou_impl!($type, $ptr, $base, false) 565 }; 566 ($type:ident, $ptr:expr, $base:expr, $negative:expr) => {{ 567 if $base == 16 && *$ptr == '0' as ::wchar_t && *$ptr.add(1) | 0x20 == 'x' as ::wchar_t { 568 $ptr = $ptr.add(2); 569 } 570 571 let mut result: $type = 0; 572 while let Some(digit) = char::from_u32(*$ptr as u32).and_then(|c| c.to_digit($base as u32)) 573 { 574 let new = result.checked_mul($base as $type).and_then(|result| { 575 if $negative { 576 result.checked_sub(digit as $type) 577 } else { 578 result.checked_add(digit as $type) 579 } 580 }); 581 result = match new { 582 Some(new) => new, 583 None => { 584 platform::errno = ERANGE; 585 return !0; 586 } 587 }; 588 589 $ptr = $ptr.add(1); 590 } 591 result 592 }}; 593 } 594 macro_rules! strto_impl { 595 ($type:ident, $ptr:expr, $base:expr) => {{ 596 let negative = *$ptr == '-' as ::wchar_t; 597 if negative { 598 $ptr = $ptr.add(1); 599 } 600 strtou_impl!($type, $ptr, $base, negative) 601 }}; 602 } 603 604 #[no_mangle] 605 pub unsafe extern "C" fn wcstol( 606 mut ptr: *const ::wchar_t, 607 end: *mut *mut ::wchar_t, 608 base: ::c_int, 609 ) -> ::c_long { 610 skipws!(ptr); 611 let result = strto_impl!(i64, ptr, base); 612 if !end.is_null() { 613 *end = ptr as *mut _; 614 } 615 result 616 } 617 618 #[no_mangle] 619 pub unsafe extern "C" fn wcstoul( 620 mut ptr: *const ::wchar_t, 621 end: *mut *mut ::wchar_t, 622 base: ::c_int, 623 ) -> ::c_ulong { 624 skipws!(ptr); 625 let result = strtou_impl!(u64, ptr, base); 626 if !end.is_null() { 627 *end = ptr as *mut _; 628 } 629 result 630 } 631 632 // #[no_mangle] 633 pub extern "C" fn wcswcs(_ws1: *const ::wchar_t, _ws2: *const ::wchar_t) -> *mut ::wchar_t { 634 unimplemented!(); 635 } 636 637 #[no_mangle] 638 pub unsafe extern "C" fn wcswidth(pwcs: *const ::wchar_t, n: ::size_t) -> ::c_int { 639 let mut total_width = 0; 640 for i in 0..n { 641 let wc_width = wcwidth(*pwcs.add(i)); 642 if wc_width < 0 { 643 return -1; 644 } 645 total_width += wc_width; 646 } 647 total_width 648 } 649 650 // #[no_mangle] 651 pub extern "C" fn wcsxfrm(_ws1: *mut ::wchar_t, _ws2: *const ::wchar_t, _n: ::size_t) -> ::size_t { 652 unimplemented!(); 653 } 654 655 #[no_mangle] 656 pub extern "C" fn wctob(c: ::wint_t) -> ::c_int { 657 if c <= 0x7F { 658 c as ::c_int 659 } else { 660 EOF 661 } 662 } 663 664 #[no_mangle] 665 pub extern "C" fn wcwidth(wc: ::wchar_t) -> ::c_int { 666 match char::from_u32(wc as u32) { 667 Some(c) => match unicode_width::UnicodeWidthChar::width(c) { 668 Some(width) => width as ::c_int, 669 None => -1, 670 }, 671 None => -1, 672 } 673 } 674 675 #[no_mangle] 676 pub unsafe extern "C" fn wmemchr(ws: *const ::wchar_t, wc: ::wchar_t, n: ::size_t) -> *mut ::wchar_t { 677 for i in 0..n { 678 if *ws.add(i) == wc { 679 return ws.add(i) as *mut ::wchar_t; 680 } 681 } 682 ptr::null_mut() 683 } 684 685 #[no_mangle] 686 pub unsafe extern "C" fn wmemcmp(ws1: *const ::wchar_t, ws2: *const ::wchar_t, n: ::size_t) -> ::c_int { 687 for i in 0..n { 688 let wc1 = *ws1.add(i); 689 let wc2 = *ws2.add(i); 690 if wc1 != wc2 { 691 return wc1 - wc2; 692 } 693 } 694 0 695 } 696 697 #[no_mangle] 698 pub unsafe extern "C" fn wmemcpy( 699 ws1: *mut ::wchar_t, 700 ws2: *const ::wchar_t, 701 n: ::size_t, 702 ) -> *mut ::wchar_t { 703 string::memcpy( 704 ws1 as *mut ::c_void, 705 ws2 as *const ::c_void, 706 n * mem::size_of::<::wchar_t>(), 707 ) as *mut ::wchar_t 708 } 709 710 #[no_mangle] 711 pub unsafe extern "C" fn wmemmove( 712 ws1: *mut ::wchar_t, 713 ws2: *const ::wchar_t, 714 n: ::size_t, 715 ) -> *mut ::wchar_t { 716 string::memmove( 717 ws1 as *mut ::c_void, 718 ws2 as *const ::c_void, 719 n * mem::size_of::<::wchar_t>(), 720 ) as *mut ::wchar_t 721 } 722 723 #[no_mangle] 724 pub unsafe extern "C" fn wmemset(ws: *mut ::wchar_t, wc: ::wchar_t, n: ::size_t) -> *mut ::wchar_t { 725 for i in 0..n { 726 *ws.add(i) = wc; 727 } 728 ws 729 } 730 731 // #[no_mangle] 732 pub extern "C" fn wprintf(_format: *const ::wchar_t, _ap: va_list) -> ::c_int { 733 unimplemented!(); 734 } 735 736 // #[no_mangle] 737 pub extern "C" fn wscanf(_format: *const ::wchar_t, _ap: va_list) -> ::c_int { 738 unimplemented!(); 739 } 740 741 #[no_mangle] 742 pub extern "C" fn wcscasecmp(mut s1: *const ::wchar_t, mut s2: *const ::wchar_t) -> ::c_int { 743 unsafe { 744 while *s1 != 0 && *s2 != 0 { 745 if towlower(*s1 as ::wint_t) != towlower(*s2 as ::wint_t) { 746 break; 747 } 748 s1 = s1.add(1); 749 s2 = s2.add(1); 750 } 751 let result = towlower(*s1 as ::wint_t).wrapping_sub(towlower(*s2 as ::wint_t)); 752 return result as ::c_int; 753 } 754 } 755 756 #[no_mangle] 757 pub extern "C" fn wcsncasecmp(mut s1: *const ::wchar_t, mut s2: *const ::wchar_t, n: ::size_t) -> ::c_int { 758 if n == 0 { 759 return 0; 760 } 761 unsafe { 762 for _ in 0..n { 763 if *s1 == 0 || *s2 == 0 || towlower(*s1 as ::wint_t) != towlower(*s2 as ::wint_t) { 764 return towlower(*s1 as ::wint_t).wrapping_sub(towlower(*s2 as ::wint_t)) as ::c_int; 765 } 766 s1 = s1.add(1); 767 s2 = s2.add(1); 768 } 769 return 0; 770 } 771 } 772