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