Manual pages: mcmcdiffmceditmcview

root/lib/strutil/strutil8bit.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. DECLARE_CTYPE_WRAPPER
  2. str_8bit_is_valid_string
  3. str_8bit_is_valid_char
  4. str_8bit_cnext_char
  5. str_8bit_cprev_char
  6. str_8bit_cnext_noncomb_char
  7. str_8bit_cprev_noncomb_char
  8. str_8bit_isspace
  9. str_8bit_ispunct
  10. str_8bit_isalnum
  11. str_8bit_isdigit
  12. str_8bit_isprint
  13. str_8bit_iscombiningmark
  14. str_8bit_toupper
  15. str_8bit_tolower
  16. str_8bit_length
  17. str_8bit_length2
  18. str_8bit_conv_gerror_message
  19. str_8bit_vfs_convert_to
  20. str_8bit_term_form
  21. str_8bit_fit_to_term
  22. str_8bit_term_trim
  23. str_8bit_term_width2
  24. str_8bit_term_width1
  25. str_8bit_term_char_width
  26. str_8bit_term_substring
  27. str_8bit_trunc
  28. str_8bit_offset_to_pos
  29. str_8bit_column_to_pos
  30. str_8bit_create_search_needle
  31. str_8bit_release_search_needle
  32. str_8bit_strdown
  33. str_8bit_search_first
  34. str_8bit_search_last
  35. str_8bit_compare
  36. str_8bit_ncompare
  37. str_8bit_casecmp
  38. str_8bit_ncasecmp
  39. str_8bit_prefix
  40. str_8bit_caseprefix
  41. str_8bit_fix_string
  42. str_8bit_create_key
  43. str_8bit_key_collate
  44. str_8bit_release_key
  45. str_8bit_init

   1 /*
   2    8bit strings utilities
   3 
   4    Copyright (C) 2007-2025
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Rostislav Benes, 2007
   9 
  10    This file is part of the Midnight Commander.
  11 
  12    The Midnight Commander is free software: you can redistribute it
  13    and/or modify it under the terms of the GNU General Public License as
  14    published by the Free Software Foundation, either version 3 of the License,
  15    or (at your option) any later version.
  16 
  17    The Midnight Commander is distributed in the hope that it will be useful,
  18    but WITHOUT ANY WARRANTY; without even the implied warranty of
  19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20    GNU General Public License for more details.
  21 
  22    You should have received a copy of the GNU General Public License
  23    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  24  */
  25 
  26 #include <config.h>
  27 
  28 #include <ctype.h>
  29 #include <stdlib.h>
  30 
  31 #include "lib/global.h"
  32 #include "lib/strutil.h"
  33 
  34 /* Functions for singlebyte encodings, all characters have width 1
  35  * using standard system functions.
  36  * There are only small differences between functions in strutil8bit.c
  37  * and strutilascii.c.
  38  */
  39 
  40 /*** global variables ****************************************************************************/
  41 
  42 /*** file scope macro definitions ****************************************************************/
  43 
  44 /*
  45  * Inlines to equalize 'char' signedness for single 'char' encodings.
  46  * Instead of writing
  47  *    isspace ((unsigned char) c);
  48  * you can write
  49  *    char_isspace (c);
  50  */
  51 #define DECLARE_CTYPE_WRAPPER(func_name)                                                           \
  52     static inline int char_##func_name (char c) { return func_name ((int) (unsigned char) c); }
  53 
  54 /*** file scope type declarations ****************************************************************/
  55 
  56 /*** forward declarations (file scope functions) *************************************************/
  57 
  58 /*** file scope variables ************************************************************************/
  59 
  60 static const char replch = '?';
  61 
  62 /* --------------------------------------------------------------------------------------------- */
  63 /*** file scope functions ************************************************************************/
  64 /* --------------------------------------------------------------------------------------------- */
  65 
  66 DECLARE_CTYPE_WRAPPER (isalnum)
     /* [previous][next][first][last][top][bottom][index][help]  */
  67 DECLARE_CTYPE_WRAPPER (isdigit)
  68 DECLARE_CTYPE_WRAPPER (isprint)
  69 DECLARE_CTYPE_WRAPPER (ispunct)
  70 DECLARE_CTYPE_WRAPPER (isspace)
  71 DECLARE_CTYPE_WRAPPER (toupper)
  72 DECLARE_CTYPE_WRAPPER (tolower)
  73 
  74 /* --------------------------------------------------------------------------------------------- */
  75 
  76 static void
  77 str_8bit_insert_replace_char (GString *buffer)
  78 {
  79     g_string_append_c (buffer, replch);
  80 }
  81 
  82 /* --------------------------------------------------------------------------------------------- */
  83 
  84 static gboolean
  85 str_8bit_is_valid_string (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
  86 {
  87     (void) text;
  88     return TRUE;
  89 }
  90 
  91 /* --------------------------------------------------------------------------------------------- */
  92 
  93 static int
  94 str_8bit_is_valid_char (const char *ch, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
  95 {
  96     (void) ch;
  97     (void) size;
  98     return 1;
  99 }
 100 
 101 /* --------------------------------------------------------------------------------------------- */
 102 
 103 static void
 104 str_8bit_cnext_char (const char **text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 105 {
 106     (*text)++;
 107 }
 108 
 109 /* --------------------------------------------------------------------------------------------- */
 110 
 111 static void
 112 str_8bit_cprev_char (const char **text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 113 {
 114     (*text)--;
 115 }
 116 
 117 /* --------------------------------------------------------------------------------------------- */
 118 
 119 static int
 120 str_8bit_cnext_noncomb_char (const char **text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 121 {
 122     if (*text[0] == '\0')
 123         return 0;
 124 
 125     (*text)++;
 126     return 1;
 127 }
 128 
 129 /* --------------------------------------------------------------------------------------------- */
 130 
 131 static int
 132 str_8bit_cprev_noncomb_char (const char **text, const char *begin)
     /* [previous][next][first][last][top][bottom][index][help]  */
 133 {
 134     if ((*text) == begin)
 135         return 0;
 136 
 137     (*text)--;
 138     return 1;
 139 }
 140 
 141 /* --------------------------------------------------------------------------------------------- */
 142 
 143 static gboolean
 144 str_8bit_isspace (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 145 {
 146     return char_isspace (text[0]) != 0;
 147 }
 148 
 149 /* --------------------------------------------------------------------------------------------- */
 150 
 151 static gboolean
 152 str_8bit_ispunct (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 153 {
 154     return char_ispunct (text[0]) != 0;
 155 }
 156 
 157 /* --------------------------------------------------------------------------------------------- */
 158 
 159 static gboolean
 160 str_8bit_isalnum (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 161 {
 162     return char_isalnum (text[0]) != 0;
 163 }
 164 
 165 /* --------------------------------------------------------------------------------------------- */
 166 
 167 static gboolean
 168 str_8bit_isdigit (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 169 {
 170     return char_isdigit (text[0]) != 0;
 171 }
 172 
 173 /* --------------------------------------------------------------------------------------------- */
 174 
 175 static gboolean
 176 str_8bit_isprint (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 177 {
 178     return char_isprint (text[0]) != 0;
 179 }
 180 
 181 /* --------------------------------------------------------------------------------------------- */
 182 
 183 static gboolean
 184 str_8bit_iscombiningmark (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 185 {
 186     (void) text;
 187     return FALSE;
 188 }
 189 
 190 /* --------------------------------------------------------------------------------------------- */
 191 
 192 static int
 193 str_8bit_toupper (const char *text, char **out, size_t *remain)
     /* [previous][next][first][last][top][bottom][index][help]  */
 194 {
 195     if (*remain <= 1)
 196         return FALSE;
 197 
 198     (*out)[0] = char_toupper (text[0]);
 199     (*out)++;
 200     (*remain)--;
 201     return TRUE;
 202 }
 203 
 204 /* --------------------------------------------------------------------------------------------- */
 205 
 206 static gboolean
 207 str_8bit_tolower (const char *text, char **out, size_t *remain)
     /* [previous][next][first][last][top][bottom][index][help]  */
 208 {
 209     if (*remain <= 1)
 210         return FALSE;
 211 
 212     (*out)[0] = char_tolower (text[0]);
 213     (*out)++;
 214     (*remain)--;
 215     return TRUE;
 216 }
 217 
 218 /* --------------------------------------------------------------------------------------------- */
 219 
 220 static int
 221 str_8bit_length (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 222 {
 223     return strlen (text);
 224 }
 225 
 226 /* --------------------------------------------------------------------------------------------- */
 227 
 228 static int
 229 str_8bit_length2 (const char *text, int size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 230 {
 231     size_t length;
 232 
 233     length = strlen (text);
 234 
 235     return (size >= 0) ? MIN (length, (size_t) size) : length;
 236 }
 237 
 238 /* --------------------------------------------------------------------------------------------- */
 239 
 240 static gchar *
 241 str_8bit_conv_gerror_message (GError *mcerror, const char *def_msg)
     /* [previous][next][first][last][top][bottom][index][help]  */
 242 {
 243     GIConv conv;
 244     gchar *ret;
 245 
 246     // glib messages are in UTF-8 charset
 247     conv = str_crt_conv_from ("UTF-8");
 248 
 249     if (conv == INVALID_CONV)
 250         ret = g_strdup (def_msg != NULL ? def_msg : "");
 251     else
 252     {
 253         GString *buf;
 254 
 255         buf = g_string_new ("");
 256 
 257         if (str_convert (conv, mcerror->message, buf) != ESTR_FAILURE)
 258             ret = g_string_free (buf, FALSE);
 259         else
 260         {
 261             ret = g_strdup (def_msg != NULL ? def_msg : "");
 262             g_string_free (buf, TRUE);
 263         }
 264 
 265         str_close_conv (conv);
 266     }
 267 
 268     return ret;
 269 }
 270 
 271 /* --------------------------------------------------------------------------------------------- */
 272 
 273 static estr_t
 274 str_8bit_vfs_convert_to (GIConv coder, const char *string, int size, GString *buffer)
     /* [previous][next][first][last][top][bottom][index][help]  */
 275 {
 276     estr_t result = ESTR_SUCCESS;
 277 
 278     if (coder == str_cnv_not_convert)
 279         g_string_append_len (buffer, string, size);
 280     else
 281         result = str_nconvert (coder, string, size, buffer);
 282 
 283     return result;
 284 }
 285 
 286 /* --------------------------------------------------------------------------------------------- */
 287 
 288 static const char *
 289 str_8bit_term_form (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 290 {
 291     static char result[BUF_MEDIUM];
 292     char *actual;
 293     size_t remain;
 294     size_t length;
 295     size_t pos = 0;
 296 
 297     actual = result;
 298     remain = sizeof (result);
 299     length = strlen (text);
 300 
 301     for (; pos < length && remain > 1; pos++, actual++, remain--)
 302         actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
 303 
 304     actual[0] = '\0';
 305     return result;
 306 }
 307 
 308 /* --------------------------------------------------------------------------------------------- */
 309 
 310 static const char *
 311 str_8bit_fit_to_term (const char *text, int width, align_crt_t just_mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 312 {
 313     static char result[BUF_MEDIUM];
 314     char *actual;
 315     size_t remain;
 316     int ident = 0;
 317     size_t length;
 318     size_t pos = 0;
 319 
 320     length = strlen (text);
 321     actual = result;
 322     remain = sizeof (result);
 323 
 324     if ((int) length <= width)
 325     {
 326         switch (HIDE_FIT (just_mode))
 327         {
 328         case J_CENTER_LEFT:
 329         case J_CENTER:
 330             ident = (width - length) / 2;
 331             break;
 332         case J_RIGHT:
 333             ident = width - length;
 334             break;
 335         default:
 336             break;
 337         }
 338 
 339         if ((int) remain <= ident)
 340             goto finally;
 341         memset (actual, ' ', ident);
 342         actual += ident;
 343         remain -= ident;
 344 
 345         for (; pos < length && remain > 1; pos++, actual++, remain--)
 346             actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
 347 
 348         if (width - length - ident > 0)
 349         {
 350             if (remain <= width - length - ident)
 351                 goto finally;
 352             memset (actual, ' ', width - length - ident);
 353             actual += width - length - ident;
 354         }
 355     }
 356     else if (IS_FIT (just_mode))
 357     {
 358         for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--)
 359             actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
 360 
 361         if (remain <= 1)
 362             goto finally;
 363         actual[0] = '~';
 364         actual++;
 365         remain--;
 366 
 367         pos += length - width + 1;
 368         for (; pos < length && remain > 1; pos++, actual++, remain--)
 369             actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
 370     }
 371     else
 372     {
 373         switch (HIDE_FIT (just_mode))
 374         {
 375         case J_CENTER:
 376             ident = (length - width) / 2;
 377             break;
 378         case J_RIGHT:
 379             ident = length - width;
 380             break;
 381         default:
 382             break;
 383         }
 384 
 385         pos += ident;
 386         for (; pos < (gsize) (ident + width) && remain > 1; pos++, actual++, remain--)
 387             actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
 388     }
 389 
 390 finally:
 391     if (actual >= result + sizeof (result))
 392         actual = result + sizeof (result) - 1;
 393     actual[0] = '\0';
 394     return result;
 395 }
 396 
 397 /* --------------------------------------------------------------------------------------------- */
 398 
 399 static const char *
 400 str_8bit_term_trim (const char *text, const ssize_t width)
     /* [previous][next][first][last][top][bottom][index][help]  */
 401 {
 402     static char result[BUF_MEDIUM];
 403     size_t remain;
 404     char *actual;
 405     size_t length;
 406 
 407     length = strlen (text);
 408     actual = result;
 409     remain = sizeof (result);
 410 
 411     if (width > 0)
 412     {
 413         size_t pos;
 414 
 415         if ((size_t) width >= length)
 416         {
 417             for (pos = 0; pos < length && remain > 1; pos++, actual++, remain--)
 418                 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
 419         }
 420         else if (width <= 3)
 421         {
 422             memset (actual, '.', (size_t) width);
 423             actual += width;
 424         }
 425         else
 426         {
 427             memset (actual, '.', 3);
 428             actual += 3;
 429             remain -= 3;
 430 
 431             for (pos = length - (size_t) width + 3; pos < length && remain > 1;
 432                  pos++, actual++, remain--)
 433                 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
 434         }
 435     }
 436 
 437     actual[0] = '\0';
 438     return result;
 439 }
 440 
 441 /* --------------------------------------------------------------------------------------------- */
 442 
 443 static size_t
 444 str_8bit_term_width2 (const char *text, const ssize_t width)
     /* [previous][next][first][last][top][bottom][index][help]  */
 445 {
 446     const size_t text_len = strlen (text);
 447 
 448     return (width < 0 ? text_len : MIN (text_len, (size_t) width));
 449 }
 450 
 451 /* --------------------------------------------------------------------------------------------- */
 452 
 453 static size_t
 454 str_8bit_term_width1 (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 455 {
 456     return str_8bit_term_width2 (text, -1);
 457 }
 458 
 459 /* --------------------------------------------------------------------------------------------- */
 460 
 461 static int
 462 str_8bit_term_char_width (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 463 {
 464     (void) text;
 465     return 1;
 466 }
 467 
 468 /* --------------------------------------------------------------------------------------------- */
 469 
 470 static const char *
 471 str_8bit_term_substring (const char *text, int start, int width)
     /* [previous][next][first][last][top][bottom][index][help]  */
 472 {
 473     static char result[BUF_MEDIUM];
 474     size_t remain;
 475     char *actual;
 476     size_t length;
 477 
 478     actual = result;
 479     remain = sizeof (result);
 480     length = strlen (text);
 481 
 482     if (start < (int) length)
 483     {
 484         size_t pos;
 485 
 486         for (pos = start; pos < length && width > 0 && remain > 1;
 487              pos++, width--, actual++, remain--)
 488             actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
 489     }
 490 
 491     for (; width > 0 && remain > 1; actual++, remain--, width--)
 492         actual[0] = ' ';
 493 
 494     actual[0] = '\0';
 495     return result;
 496 }
 497 
 498 /* --------------------------------------------------------------------------------------------- */
 499 
 500 static const char *
 501 str_8bit_trunc (const char *text, const ssize_t width)
     /* [previous][next][first][last][top][bottom][index][help]  */
 502 {
 503     static char result[MC_MAXPATHLEN];
 504     int remain;
 505     char *actual;
 506     size_t pos = 0;
 507     size_t length;
 508 
 509     actual = result;
 510     remain = sizeof (result);
 511     length = strlen (text);
 512 
 513     if (width >= 0 && length > (size_t) width)
 514     {
 515         for (; pos + 1 <= (size_t) width / 2 && remain > 1; actual++, pos++, remain--)
 516             actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
 517 
 518         if (remain <= 1)
 519             goto finally;
 520         actual[0] = '~';
 521         actual++;
 522         remain--;
 523 
 524         pos += length - (size_t) width + 1;
 525         for (; pos < length && remain > 1; pos++, actual++, remain--)
 526             actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
 527     }
 528     else
 529     {
 530         for (; pos < length && remain > 1; pos++, actual++, remain--)
 531             actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
 532     }
 533 
 534 finally:
 535     actual[0] = '\0';
 536     return result;
 537 }
 538 
 539 /* --------------------------------------------------------------------------------------------- */
 540 
 541 static int
 542 str_8bit_offset_to_pos (const char *text, size_t length)
     /* [previous][next][first][last][top][bottom][index][help]  */
 543 {
 544     (void) text;
 545     return (int) length;
 546 }
 547 
 548 /* --------------------------------------------------------------------------------------------- */
 549 
 550 static int
 551 str_8bit_column_to_pos (const char *text, size_t pos)
     /* [previous][next][first][last][top][bottom][index][help]  */
 552 {
 553     (void) text;
 554     return (int) pos;
 555 }
 556 
 557 /* --------------------------------------------------------------------------------------------- */
 558 
 559 static char *
 560 str_8bit_create_search_needle (const char *needle, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 561 {
 562     (void) case_sen;
 563     return (char *) needle;
 564 }
 565 
 566 /* --------------------------------------------------------------------------------------------- */
 567 
 568 static void
 569 str_8bit_release_search_needle (char *needle, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 570 {
 571     (void) case_sen;
 572     (void) needle;
 573 }
 574 
 575 /* --------------------------------------------------------------------------------------------- */
 576 
 577 static char *
 578 str_8bit_strdown (const char *str)
     /* [previous][next][first][last][top][bottom][index][help]  */
 579 {
 580     char *rets, *p;
 581 
 582     if (str == NULL)
 583         return NULL;
 584 
 585     rets = g_strdup (str);
 586 
 587     for (p = rets; *p != '\0'; p++)
 588         *p = char_tolower (*p);
 589 
 590     return rets;
 591 }
 592 
 593 /* --------------------------------------------------------------------------------------------- */
 594 
 595 static const char *
 596 str_8bit_search_first (const char *text, const char *search, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 597 {
 598     char *fold_text;
 599     char *fold_search;
 600     const char *match;
 601 
 602     fold_text = case_sen ? (char *) text : str_8bit_strdown (text);
 603     fold_search = case_sen ? (char *) search : str_8bit_strdown (search);
 604 
 605     match = g_strstr_len (fold_text, -1, fold_search);
 606     if (match != NULL)
 607     {
 608         size_t offset;
 609 
 610         offset = match - fold_text;
 611         match = text + offset;
 612     }
 613 
 614     if (!case_sen)
 615     {
 616         g_free (fold_text);
 617         g_free (fold_search);
 618     }
 619 
 620     return match;
 621 }
 622 
 623 /* --------------------------------------------------------------------------------------------- */
 624 
 625 static const char *
 626 str_8bit_search_last (const char *text, const char *search, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 627 {
 628     char *fold_text;
 629     char *fold_search;
 630     const char *match;
 631 
 632     fold_text = case_sen ? (char *) text : str_8bit_strdown (text);
 633     fold_search = case_sen ? (char *) search : str_8bit_strdown (search);
 634 
 635     match = g_strrstr_len (fold_text, -1, fold_search);
 636     if (match != NULL)
 637     {
 638         size_t offset;
 639 
 640         offset = match - fold_text;
 641         match = text + offset;
 642     }
 643 
 644     if (!case_sen)
 645     {
 646         g_free (fold_text);
 647         g_free (fold_search);
 648     }
 649 
 650     return match;
 651 }
 652 
 653 /* --------------------------------------------------------------------------------------------- */
 654 
 655 static int
 656 str_8bit_compare (const char *t1, const char *t2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 657 {
 658     return strcmp (t1, t2);
 659 }
 660 
 661 /* --------------------------------------------------------------------------------------------- */
 662 
 663 static int
 664 str_8bit_ncompare (const char *t1, const char *t2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 665 {
 666     size_t l1, l2;
 667 
 668     l1 = strlen (t1);
 669     l2 = strlen (t2);
 670 
 671     return strncmp (t1, t2, MIN (l1, l2));
 672 }
 673 
 674 /* --------------------------------------------------------------------------------------------- */
 675 
 676 static int
 677 str_8bit_casecmp (const char *s1, const char *s2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 678 {
 679     // code from GLib
 680 
 681 #ifdef HAVE_STRCASECMP
 682     g_return_val_if_fail (s1 != NULL, 0);
 683     g_return_val_if_fail (s2 != NULL, 0);
 684 
 685     return strcasecmp (s1, s2);
 686 #else
 687 
 688     g_return_val_if_fail (s1 != NULL, 0);
 689     g_return_val_if_fail (s2 != NULL, 0);
 690 
 691     for (; *s1 != '\0' && *s2 != '\0'; s1++, s2++)
 692     {
 693         gint c1, c2;
 694 
 695         /* According to A. Cox, some platforms have islower's that
 696          * don't work right on non-uppercase
 697          */
 698         c1 = isupper ((guchar) *s1) ? tolower ((guchar) *s1) : *s1;
 699         c2 = isupper ((guchar) *s2) ? tolower ((guchar) *s2) : *s2;
 700         if (c1 != c2)
 701             return (c1 - c2);
 702     }
 703 
 704     return (((gint) (guchar) *s1) - ((gint) (guchar) *s2));
 705 #endif
 706 }
 707 
 708 /* --------------------------------------------------------------------------------------------- */
 709 
 710 static int
 711 str_8bit_ncasecmp (const char *s1, const char *s2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 712 {
 713     size_t l1, l2;
 714     size_t n;
 715 
 716     g_return_val_if_fail (s1 != NULL, 0);
 717     g_return_val_if_fail (s2 != NULL, 0);
 718 
 719     l1 = strlen (s1);
 720     l2 = strlen (s2);
 721     n = MIN (l1, l2);
 722 
 723     // code from GLib
 724 
 725 #ifdef HAVE_STRNCASECMP
 726     return strncasecmp (s1, s2, n);
 727 #else
 728 
 729     for (; *s1 != '\0' && *s2 != '\0'; s1++, s2++)
 730     {
 731         gint c1, c2;
 732 
 733         n--;
 734         /* According to A. Cox, some platforms have islower's that
 735          * don't work right on non-uppercase
 736          */
 737         c1 = isupper ((guchar) *s1) ? tolower ((guchar) *s1) : *s1;
 738         c2 = isupper ((guchar) *s2) ? tolower ((guchar) *s2) : *s2;
 739         if (c1 != c2)
 740             return (c1 - c2);
 741     }
 742 
 743     if (n == 0)
 744         return 0;
 745 
 746     return (((gint) (guchar) *s1) - ((gint) (guchar) *s2));
 747 
 748 #endif
 749 }
 750 
 751 /* --------------------------------------------------------------------------------------------- */
 752 
 753 static int
 754 str_8bit_prefix (const char *text, const char *prefix)
     /* [previous][next][first][last][top][bottom][index][help]  */
 755 {
 756     int result;
 757 
 758     for (result = 0;
 759          text[result] != '\0' && prefix[result] != '\0' && text[result] == prefix[result]; result++)
 760         ;
 761 
 762     return result;
 763 }
 764 
 765 /* --------------------------------------------------------------------------------------------- */
 766 
 767 static int
 768 str_8bit_caseprefix (const char *text, const char *prefix)
     /* [previous][next][first][last][top][bottom][index][help]  */
 769 {
 770     int result;
 771 
 772     for (result = 0; text[result] != '\0' && prefix[result] != '\0'
 773          && char_toupper (text[result]) == char_toupper (prefix[result]);
 774          result++)
 775         ;
 776 
 777     return result;
 778 }
 779 
 780 /* --------------------------------------------------------------------------------------------- */
 781 
 782 static void
 783 str_8bit_fix_string (char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 784 {
 785     (void) text;
 786 }
 787 
 788 /* --------------------------------------------------------------------------------------------- */
 789 
 790 static char *
 791 str_8bit_create_key (const char *text, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 792 {
 793     return case_sen ? (char *) text : str_8bit_strdown (text);
 794 }
 795 
 796 /* --------------------------------------------------------------------------------------------- */
 797 
 798 static int
 799 str_8bit_key_collate (const char *t1, const char *t2, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 800 {
 801     return case_sen ? strcmp (t1, t2) : strcoll (t1, t2);
 802 }
 803 
 804 /* --------------------------------------------------------------------------------------------- */
 805 
 806 static void
 807 str_8bit_release_key (char *key, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 808 {
 809     if (!case_sen)
 810         g_free (key);
 811 }
 812 
 813 /* --------------------------------------------------------------------------------------------- */
 814 /*** public functions ****************************************************************************/
 815 /* --------------------------------------------------------------------------------------------- */
 816 
 817 struct str_class
 818 str_8bit_init (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 819 {
 820     struct str_class result;
 821 
 822     result.conv_gerror_message = str_8bit_conv_gerror_message;
 823     result.vfs_convert_to = str_8bit_vfs_convert_to;
 824     result.insert_replace_char = str_8bit_insert_replace_char;
 825     result.is_valid_string = str_8bit_is_valid_string;
 826     result.is_valid_char = str_8bit_is_valid_char;
 827     result.cnext_char = str_8bit_cnext_char;
 828     result.cprev_char = str_8bit_cprev_char;
 829     result.cnext_char_safe = str_8bit_cnext_char;
 830     result.cprev_char_safe = str_8bit_cprev_char;
 831     result.cnext_noncomb_char = str_8bit_cnext_noncomb_char;
 832     result.cprev_noncomb_char = str_8bit_cprev_noncomb_char;
 833     result.char_isspace = str_8bit_isspace;
 834     result.char_ispunct = str_8bit_ispunct;
 835     result.char_isalnum = str_8bit_isalnum;
 836     result.char_isdigit = str_8bit_isdigit;
 837     result.char_isprint = str_8bit_isprint;
 838     result.char_iscombiningmark = str_8bit_iscombiningmark;
 839     result.char_toupper = str_8bit_toupper;
 840     result.char_tolower = str_8bit_tolower;
 841     result.length = str_8bit_length;
 842     result.length2 = str_8bit_length2;
 843     result.length_noncomb = str_8bit_length;
 844     result.fix_string = str_8bit_fix_string;
 845     result.term_form = str_8bit_term_form;
 846     result.fit_to_term = str_8bit_fit_to_term;
 847     result.term_trim = str_8bit_term_trim;
 848     result.term_width2 = str_8bit_term_width2;
 849     result.term_width1 = str_8bit_term_width1;
 850     result.term_char_width = str_8bit_term_char_width;
 851     result.term_substring = str_8bit_term_substring;
 852     result.trunc = str_8bit_trunc;
 853     result.offset_to_pos = str_8bit_offset_to_pos;
 854     result.column_to_pos = str_8bit_column_to_pos;
 855     result.create_search_needle = str_8bit_create_search_needle;
 856     result.release_search_needle = str_8bit_release_search_needle;
 857     result.search_first = str_8bit_search_first;
 858     result.search_last = str_8bit_search_last;
 859     result.compare = str_8bit_compare;
 860     result.ncompare = str_8bit_ncompare;
 861     result.casecmp = str_8bit_casecmp;
 862     result.ncasecmp = str_8bit_ncasecmp;
 863     result.prefix = str_8bit_prefix;
 864     result.caseprefix = str_8bit_caseprefix;
 865     result.create_key = str_8bit_create_key;
 866     result.create_key_for_filename = str_8bit_create_key;
 867     result.key_collate = str_8bit_key_collate;
 868     result.release_key = str_8bit_release_key;
 869 
 870     return result;
 871 }
 872 
 873 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */