1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org> 5 * Copyright (C) 2012 Oleg Moskalenko <mom040267@gmail.com> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 #include <ctype.h> 32 #include <errno.h> 33 #include <err.h> 34 #include <langinfo.h> 35 #include <math.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <wchar.h> 39 #include <wctype.h> 40 41 #include "bwstring.h" 42 #include "sort.h" 43 44 bool byte_sort; 45 46 static wchar_t **wmonths; 47 static char **cmonths; 48 49 /* initialise months */ 50 51 void 52 initialise_months(void) 53 { 54 const nl_item item[12] = { ABMON_1, ABMON_2, ABMON_3, ABMON_4, 55 ABMON_5, ABMON_6, ABMON_7, ABMON_8, ABMON_9, ABMON_10, 56 ABMON_11, ABMON_12 }; 57 char *tmp; 58 size_t len; 59 60 if (mb_cur_max == 1) { 61 if (cmonths == NULL) { 62 char *m; 63 64 cmonths = sort_malloc(sizeof(char*) * 12); 65 for (int i = 0; i < 12; i++) { 66 cmonths[i] = NULL; 67 tmp = nl_langinfo(item[i]); 68 if (debug_sort) 69 printf("month[%d]=%s\n", i, tmp); 70 if (*tmp == '\0') 71 continue; 72 m = sort_strdup(tmp); 73 len = strlen(tmp); 74 for (unsigned int j = 0; j < len; j++) 75 m[j] = toupper(m[j]); 76 cmonths[i] = m; 77 } 78 } 79 80 } else { 81 if (wmonths == NULL) { 82 wchar_t *m; 83 84 wmonths = sort_malloc(sizeof(wchar_t *) * 12); 85 for (int i = 0; i < 12; i++) { 86 wmonths[i] = NULL; 87 tmp = nl_langinfo(item[i]); 88 if (debug_sort) 89 printf("month[%d]=%s\n", i, tmp); 90 if (*tmp == '\0') 91 continue; 92 len = strlen(tmp); 93 m = sort_malloc(SIZEOF_WCHAR_STRING(len + 1)); 94 if (mbstowcs(m, tmp, len) == 95 ((size_t) - 1)) { 96 sort_free(m); 97 continue; 98 } 99 m[len] = L'\0'; 100 for (unsigned int j = 0; j < len; j++) 101 m[j] = towupper(m[j]); 102 wmonths[i] = m; 103 } 104 } 105 } 106 } 107 108 /* 109 * Compare two wide-character strings 110 */ 111 static int 112 wide_str_coll(const wchar_t *s1, const wchar_t *s2) 113 { 114 int ret; 115 116 errno = 0; 117 ret = wcscoll(s1, s2); 118 if (errno == EILSEQ) { 119 errno = 0; 120 ret = wcscmp(s1, s2); 121 if (errno != 0) { 122 for (size_t i = 0; ; ++i) { 123 wchar_t c1 = s1[i]; 124 wchar_t c2 = s2[i]; 125 if (c1 == L'\0') 126 return ((c2 == L'\0') ? 0 : -1); 127 if (c2 == L'\0') 128 return (+1); 129 if (c1 == c2) 130 continue; 131 return ((int)(c1 - c2)); 132 } 133 } 134 } 135 return (ret); 136 } 137 138 /* counterparts of wcs functions */ 139 140 void 141 bwsprintf(FILE *f, struct bwstring *bws, const char *prefix, const char *suffix) 142 { 143 144 if (mb_cur_max == 1) 145 fprintf(f, "%s%s%s", prefix, bws->cdata.str, suffix); 146 else 147 fprintf(f, "%s%S%s", prefix, bws->wdata.str, suffix); 148 } 149 150 const void* bwsrawdata(const struct bwstring *bws) 151 { 152 153 return (bws->wdata.str); 154 } 155 156 size_t bwsrawlen(const struct bwstring *bws) 157 { 158 159 return ((mb_cur_max == 1) ? bws->cdata.len : 160 SIZEOF_WCHAR_STRING(bws->wdata.len)); 161 } 162 163 size_t 164 bws_memsize(const struct bwstring *bws) 165 { 166 167 return ((mb_cur_max == 1) ? 168 (bws->cdata.len + 2 + sizeof(struct bwstring)) : 169 (SIZEOF_WCHAR_STRING(bws->wdata.len + 1) + sizeof(struct bwstring))); 170 } 171 172 void 173 bws_setlen(struct bwstring *bws, size_t newlen) 174 { 175 176 if (mb_cur_max == 1 && bws && newlen != bws->cdata.len && 177 newlen <= bws->cdata.len) { 178 bws->cdata.len = newlen; 179 bws->cdata.str[newlen] = '\0'; 180 } else if (bws && newlen != bws->wdata.len && newlen <= bws->wdata.len) { 181 bws->wdata.len = newlen; 182 bws->wdata.str[newlen] = L'\0'; 183 } 184 } 185 186 /* 187 * Allocate a new binary string of specified size 188 */ 189 struct bwstring * 190 bwsalloc(size_t sz) 191 { 192 struct bwstring *ret; 193 194 if (mb_cur_max == 1) { 195 ret = sort_malloc(sizeof(struct bwstring) + 1 + sz); 196 ret->cdata.len = sz; 197 ret->cdata.str[sz] = '\0'; 198 } else { 199 ret = sort_malloc( 200 sizeof(struct bwstring) + SIZEOF_WCHAR_STRING(sz + 1)); 201 ret->wdata.len = sz; 202 ret->wdata.str[sz] = L'\0'; 203 } 204 205 return (ret); 206 } 207 208 /* 209 * Create a copy of binary string. 210 * New string size equals the length of the old string. 211 */ 212 struct bwstring * 213 bwsdup(const struct bwstring *s) 214 { 215 216 if (s == NULL) 217 return (NULL); 218 else { 219 struct bwstring *ret = bwsalloc(BWSLEN(s)); 220 221 if (mb_cur_max == 1) 222 memcpy(ret->cdata.str, s->cdata.str, (s->cdata.len)); 223 else 224 memcpy(ret->wdata.str, s->wdata.str, 225 SIZEOF_WCHAR_STRING(s->wdata.len)); 226 227 return (ret); 228 } 229 } 230 231 /* 232 * Create a new binary string from a wide character buffer. 233 */ 234 struct bwstring * 235 bwssbdup(const wchar_t *str, size_t len) 236 { 237 238 if (str == NULL) 239 return ((len == 0) ? bwsalloc(0) : NULL); 240 else { 241 struct bwstring *ret; 242 243 ret = bwsalloc(len); 244 245 if (mb_cur_max == 1) 246 for (size_t i = 0; i < len; ++i) 247 ret->cdata.str[i] = (char)str[i]; 248 else 249 memcpy(ret->wdata.str, str, SIZEOF_WCHAR_STRING(len)); 250 251 return (ret); 252 } 253 } 254 255 /* 256 * Create a new binary string from a raw binary buffer. 257 */ 258 struct bwstring * 259 bwscsbdup(const unsigned char *str, size_t len) 260 { 261 struct bwstring *ret; 262 263 ret = bwsalloc(len); 264 265 if (str) { 266 if (mb_cur_max == 1) 267 memcpy(ret->cdata.str, str, len); 268 else { 269 mbstate_t mbs; 270 const char *s; 271 size_t charlen, chars, cptr; 272 273 chars = 0; 274 cptr = 0; 275 s = (const char *) str; 276 277 memset(&mbs, 0, sizeof(mbs)); 278 279 while (cptr < len) { 280 size_t n = mb_cur_max; 281 282 if (n > len - cptr) 283 n = len - cptr; 284 charlen = mbrlen(s + cptr, n, &mbs); 285 switch (charlen) { 286 case 0: 287 /* FALLTHROUGH */ 288 case (size_t) -1: 289 /* FALLTHROUGH */ 290 case (size_t) -2: 291 ret->wdata.str[chars++] = 292 (unsigned char) s[cptr]; 293 ++cptr; 294 break; 295 default: 296 n = mbrtowc(ret->wdata.str + (chars++), 297 s + cptr, charlen, &mbs); 298 if ((n == (size_t)-1) || (n == (size_t)-2)) 299 /* NOTREACHED */ 300 err(2, "mbrtowc error"); 301 cptr += charlen; 302 } 303 } 304 305 ret->wdata.len = chars; 306 ret->wdata.str[ret->wdata.len] = L'\0'; 307 } 308 } 309 return (ret); 310 } 311 312 /* 313 * De-allocate object memory 314 */ 315 void 316 bwsfree(const struct bwstring *s) 317 { 318 319 if (s) 320 sort_free(s); 321 } 322 323 /* 324 * Copy content of src binary string to dst, 325 * with specified number of symbols to be copied. 326 * An offset value can be specified, from the start of src string. 327 * If the capacity of the dst string is not sufficient, 328 * then the data is truncated. 329 */ 330 struct bwstring * 331 bwsnocpy(struct bwstring *dst, const struct bwstring *src, size_t offset, 332 size_t size) 333 { 334 335 if (offset >= BWSLEN(src)) { 336 bws_setlen(dst, 0); 337 } else { 338 size_t nums = BWSLEN(src) - offset; 339 340 if (nums > BWSLEN(dst)) 341 nums = BWSLEN(dst); 342 if (nums > size) 343 nums = size; 344 if (mb_cur_max == 1) { 345 memcpy(dst->cdata.str, src->cdata.str + offset, nums); 346 dst->cdata.len = nums; 347 dst->cdata.str[nums] = '\0'; 348 } else { 349 memcpy(dst->wdata.str, src->wdata.str + offset, 350 SIZEOF_WCHAR_STRING(nums)); 351 dst->wdata.len = nums; 352 dst->wdata.str[nums] = L'\0'; 353 } 354 } 355 return (dst); 356 } 357 358 /* 359 * Write binary string to the file. 360 * The output is ended either with '\n' (nl == true) 361 * or '\0' (nl == false). 362 */ 363 size_t 364 bwsfwrite(struct bwstring *bws, FILE *f, bool zero_ended) 365 { 366 367 if (mb_cur_max == 1) { 368 size_t len = bws->cdata.len; 369 370 if (!zero_ended) { 371 bws->cdata.str[len] = '\n'; 372 373 if (fwrite(bws->cdata.str, len + 1, 1, f) < 1) 374 err(2, NULL); 375 376 bws->cdata.str[len] = '\0'; 377 } else if (fwrite(bws->cdata.str, len + 1, 1, f) < 1) 378 err(2, NULL); 379 380 return (len + 1); 381 382 } else { 383 wchar_t eols; 384 size_t printed = 0; 385 386 eols = zero_ended ? btowc('\0') : btowc('\n'); 387 388 while (printed < BWSLEN(bws)) { 389 const wchar_t *s = bws->wdata.str + printed; 390 391 if (*s == L'\0') { 392 int nums; 393 394 nums = fwprintf(f, L"%lc", *s); 395 396 if (nums != 1) 397 err(2, NULL); 398 ++printed; 399 } else { 400 int nums; 401 402 nums = fwprintf(f, L"%ls", s); 403 404 if (nums < 1) 405 err(2, NULL); 406 printed += nums; 407 } 408 } 409 fwprintf(f, L"%lc", eols); 410 return (printed + 1); 411 } 412 } 413 414 int 415 bwsncmp(const struct bwstring *bws1, const struct bwstring *bws2, 416 size_t offset, size_t len) 417 { 418 size_t cmp_len, len1, len2; 419 int res; 420 421 len1 = BWSLEN(bws1); 422 len2 = BWSLEN(bws2); 423 424 if (len1 <= offset) { 425 return ((len2 <= offset) ? 0 : -1); 426 } else { 427 if (len2 <= offset) 428 return (+1); 429 else { 430 len1 -= offset; 431 len2 -= offset; 432 433 cmp_len = len1; 434 435 if (len2 < cmp_len) 436 cmp_len = len2; 437 438 if (len < cmp_len) 439 cmp_len = len; 440 441 if (mb_cur_max == 1) { 442 const char *s1, *s2; 443 444 s1 = bws1->cdata.str + offset; 445 s2 = bws2->cdata.str + offset; 446 447 res = memcmp(s1, s2, cmp_len); 448 449 } else { 450 const wchar_t *s1, *s2; 451 452 s1 = bws1->wdata.str + offset; 453 s2 = bws2->wdata.str + offset; 454 455 res = memcmp(s1, s2, SIZEOF_WCHAR_STRING(cmp_len)); 456 } 457 } 458 } 459 460 if (res == 0) { 461 if (len1 < cmp_len && len1 < len2) 462 res = -1; 463 else if (len2 < cmp_len && len2 < len1) 464 res = +1; 465 } 466 467 return (res); 468 } 469 470 int 471 bwscmp(const struct bwstring *bws1, const struct bwstring *bws2, size_t offset) 472 { 473 size_t len1, len2, cmp_len; 474 int res; 475 476 len1 = BWSLEN(bws1); 477 len2 = BWSLEN(bws2); 478 479 len1 -= offset; 480 len2 -= offset; 481 482 cmp_len = len1; 483 484 if (len2 < cmp_len) 485 cmp_len = len2; 486 487 res = bwsncmp(bws1, bws2, offset, cmp_len); 488 489 if (res == 0) { 490 if( len1 < len2) 491 res = -1; 492 else if (len2 < len1) 493 res = +1; 494 } 495 496 return (res); 497 } 498 499 int 500 bws_iterator_cmp(bwstring_iterator iter1, bwstring_iterator iter2, size_t len) 501 { 502 wchar_t c1, c2; 503 size_t i; 504 505 for (i = 0; i < len; ++i) { 506 c1 = bws_get_iter_value(iter1); 507 c2 = bws_get_iter_value(iter2); 508 if (c1 != c2) 509 return (c1 - c2); 510 iter1 = bws_iterator_inc(iter1, 1); 511 iter2 = bws_iterator_inc(iter2, 1); 512 } 513 514 return (0); 515 } 516 517 int 518 bwscoll(const struct bwstring *bws1, const struct bwstring *bws2, size_t offset) 519 { 520 size_t len1, len2; 521 522 len1 = BWSLEN(bws1); 523 len2 = BWSLEN(bws2); 524 525 if (len1 <= offset) 526 return ((len2 <= offset) ? 0 : -1); 527 else { 528 if (len2 <= offset) 529 return (+1); 530 else { 531 len1 -= offset; 532 len2 -= offset; 533 534 if (mb_cur_max == 1) { 535 const char *s1, *s2; 536 537 s1 = bws1->cdata.str + offset; 538 s2 = bws2->cdata.str + offset; 539 540 if (byte_sort) { 541 int res; 542 543 if (len1 > len2) { 544 res = memcmp(s1, s2, len2); 545 if (!res) 546 res = +1; 547 } else if (len1 < len2) { 548 res = memcmp(s1, s2, len1); 549 if (!res) 550 res = -1; 551 } else 552 res = memcmp(s1, s2, len1); 553 554 return (res); 555 556 } else { 557 int res; 558 size_t i, maxlen; 559 560 i = 0; 561 maxlen = len1; 562 563 if (maxlen > len2) 564 maxlen = len2; 565 566 while (i < maxlen) { 567 /* goto next non-zero part: */ 568 while ((i < maxlen) && 569 !s1[i] && !s2[i]) 570 ++i; 571 572 if (i >= maxlen) 573 break; 574 575 if (s1[i] == 0) { 576 if (s2[i] == 0) 577 /* NOTREACHED */ 578 err(2, "bwscoll error 01"); 579 else 580 return (-1); 581 } else if (s2[i] == 0) 582 return (+1); 583 584 res = strcoll((const char*)(s1 + i), (const char*)(s2 + i)); 585 if (res) 586 return (res); 587 588 while ((i < maxlen) && 589 s1[i] && s2[i]) 590 ++i; 591 592 if (i >= maxlen) 593 break; 594 595 if (s1[i] == 0) { 596 if (s2[i] == 0) { 597 ++i; 598 continue; 599 } else 600 return (-1); 601 } else if (s2[i] == 0) 602 return (+1); 603 else 604 /* NOTREACHED */ 605 err(2, "bwscoll error 02"); 606 } 607 608 if (len1 < len2) 609 return (-1); 610 else if (len1 > len2) 611 return (+1); 612 613 return (0); 614 } 615 } else { 616 const wchar_t *s1, *s2; 617 size_t i, maxlen; 618 int res; 619 620 s1 = bws1->wdata.str + offset; 621 s2 = bws2->wdata.str + offset; 622 623 i = 0; 624 maxlen = len1; 625 626 if (maxlen > len2) 627 maxlen = len2; 628 629 while (i < maxlen) { 630 631 /* goto next non-zero part: */ 632 while ((i < maxlen) && 633 !s1[i] && !s2[i]) 634 ++i; 635 636 if (i >= maxlen) 637 break; 638 639 if (s1[i] == 0) { 640 if (s2[i] == 0) 641 /* NOTREACHED */ 642 err(2, "bwscoll error 1"); 643 else 644 return (-1); 645 } else if (s2[i] == 0) 646 return (+1); 647 648 res = wide_str_coll(s1 + i, s2 + i); 649 if (res) 650 return (res); 651 652 while ((i < maxlen) && s1[i] && s2[i]) 653 ++i; 654 655 if (i >= maxlen) 656 break; 657 658 if (s1[i] == 0) { 659 if (s2[i] == 0) { 660 ++i; 661 continue; 662 } else 663 return (-1); 664 } else if (s2[i] == 0) 665 return (+1); 666 else 667 /* NOTREACHED */ 668 err(2, "bwscoll error 2"); 669 } 670 671 if (len1 < len2) 672 return (-1); 673 else if (len1 > len2) 674 return (+1); 675 676 return (0); 677 } 678 } 679 } 680 } 681 682 /* 683 * Correction of the system API 684 */ 685 double 686 bwstod(struct bwstring *s0, bool *empty) 687 { 688 double ret; 689 690 if (mb_cur_max == 1) { 691 char *end, *s; 692 char *ep; 693 694 s = s0->cdata.str; 695 end = s + s0->cdata.len; 696 ep = NULL; 697 698 while (isblank(*s) && s < end) 699 ++s; 700 701 if (!isprint(*s)) { 702 *empty = true; 703 return (0); 704 } 705 706 ret = strtod((char*)s, &ep); 707 if (ep == s) { 708 *empty = true; 709 return (0); 710 } 711 } else { 712 wchar_t *end, *ep, *s; 713 714 s = s0->wdata.str; 715 end = s + s0->wdata.len; 716 ep = NULL; 717 718 while (iswblank(*s) && s < end) 719 ++s; 720 721 if (!iswprint(*s)) { 722 *empty = true; 723 return (0); 724 } 725 726 ret = wcstod(s, &ep); 727 if (ep == s) { 728 *empty = true; 729 return (0); 730 } 731 } 732 733 *empty = false; 734 return (ret); 735 } 736 737 /* 738 * A helper function for monthcoll. If a line matches 739 * a month name, it returns (number of the month - 1), 740 * while if there is no match, it just return -1. 741 */ 742 743 int 744 bws_month_score(const struct bwstring *s0) 745 { 746 747 if (mb_cur_max == 1) { 748 const char *end, *s; 749 750 s = s0->cdata.str; 751 end = s + s0->cdata.len; 752 753 while (isblank(*s) && s < end) 754 ++s; 755 756 for (int i = 11; i >= 0; --i) { 757 if (cmonths[i] && 758 (s == strstr(s, cmonths[i]))) 759 return (i); 760 } 761 762 } else { 763 const wchar_t *end, *s; 764 765 s = s0->wdata.str; 766 end = s + s0->wdata.len; 767 768 while (iswblank(*s) && s < end) 769 ++s; 770 771 for (int i = 11; i >= 0; --i) { 772 if (wmonths[i] && (s == wcsstr(s, wmonths[i]))) 773 return (i); 774 } 775 } 776 777 return (-1); 778 } 779 780 /* 781 * Rips out leading blanks (-b). 782 */ 783 struct bwstring * 784 ignore_leading_blanks(struct bwstring *str) 785 { 786 787 if (mb_cur_max == 1) { 788 char *dst, *end, *src; 789 790 src = str->cdata.str; 791 dst = src; 792 end = src + str->cdata.len; 793 794 while (src < end && isblank(*src)) 795 ++src; 796 797 if (src != dst) { 798 size_t newlen; 799 800 newlen = BWSLEN(str) - (src - dst); 801 802 while (src < end) { 803 *dst = *src; 804 ++dst; 805 ++src; 806 } 807 bws_setlen(str, newlen); 808 } 809 } else { 810 wchar_t *dst, *end, *src; 811 812 src = str->wdata.str; 813 dst = src; 814 end = src + str->wdata.len; 815 816 while (src < end && iswblank(*src)) 817 ++src; 818 819 if (src != dst) { 820 821 size_t newlen = BWSLEN(str) - (src - dst); 822 823 while (src < end) { 824 *dst = *src; 825 ++dst; 826 ++src; 827 } 828 bws_setlen(str, newlen); 829 830 } 831 } 832 return (str); 833 } 834 835 /* 836 * Rips out nonprinting characters (-i). 837 */ 838 struct bwstring * 839 ignore_nonprinting(struct bwstring *str) 840 { 841 size_t newlen = BWSLEN(str); 842 843 if (mb_cur_max == 1) { 844 char *dst, *end, *src; 845 char c; 846 847 src = str->cdata.str; 848 dst = src; 849 end = src + str->cdata.len; 850 851 while (src < end) { 852 c = *src; 853 if (isprint(c)) { 854 *dst = c; 855 ++dst; 856 ++src; 857 } else { 858 ++src; 859 --newlen; 860 } 861 } 862 } else { 863 wchar_t *dst, *end, *src; 864 wchar_t c; 865 866 src = str->wdata.str; 867 dst = src; 868 end = src + str->wdata.len; 869 870 while (src < end) { 871 c = *src; 872 if (iswprint(c)) { 873 *dst = c; 874 ++dst; 875 ++src; 876 } else { 877 ++src; 878 --newlen; 879 } 880 } 881 } 882 bws_setlen(str, newlen); 883 884 return (str); 885 } 886 887 /* 888 * Rips out any characters that are not alphanumeric characters 889 * nor blanks (-d). 890 */ 891 struct bwstring * 892 dictionary_order(struct bwstring *str) 893 { 894 size_t newlen = BWSLEN(str); 895 896 if (mb_cur_max == 1) { 897 char *dst, *end, *src; 898 char c; 899 900 src = str->cdata.str; 901 dst = src; 902 end = src + str->cdata.len; 903 904 while (src < end) { 905 c = *src; 906 if (isalnum(c) || isblank(c)) { 907 *dst = c; 908 ++dst; 909 ++src; 910 } else { 911 ++src; 912 --newlen; 913 } 914 } 915 } else { 916 wchar_t *dst, *end, *src; 917 wchar_t c; 918 919 src = str->wdata.str; 920 dst = src; 921 end = src + str->wdata.len; 922 923 while (src < end) { 924 c = *src; 925 if (iswalnum(c) || iswblank(c)) { 926 *dst = c; 927 ++dst; 928 ++src; 929 } else { 930 ++src; 931 --newlen; 932 } 933 } 934 } 935 bws_setlen(str, newlen); 936 937 return (str); 938 } 939 940 /* 941 * Converts string to lower case(-f). 942 */ 943 struct bwstring * 944 ignore_case(struct bwstring *str) 945 { 946 947 if (mb_cur_max == 1) { 948 char *end, *s; 949 950 s = str->cdata.str; 951 end = s + str->cdata.len; 952 953 while (s < end) { 954 *s = toupper(*s); 955 ++s; 956 } 957 } else { 958 wchar_t *end, *s; 959 960 s = str->wdata.str; 961 end = s + str->wdata.len; 962 963 while (s < end) { 964 *s = towupper(*s); 965 ++s; 966 } 967 } 968 return (str); 969 } 970 971 void 972 bws_disorder_warnx(struct bwstring *s, const char *fn, size_t pos) 973 { 974 975 if (mb_cur_max == 1) 976 warnx("%s:%zu: disorder: %s", fn, pos + 1, s->cdata.str); 977 else 978 warnx("%s:%zu: disorder: %ls", fn, pos + 1, s->wdata.str); 979 } 980