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, int 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 (width >= (int) 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, '.', width);
 423             actual += width;
 424         }
 425         else
 426         {
 427             memset (actual, '.', 3);
 428             actual += 3;
 429             remain -= 3;
 430 
 431             for (pos = length - width + 3; pos < length && remain > 1; pos++, actual++, remain--)
 432                 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
 433         }
 434     }
 435 
 436     actual[0] = '\0';
 437     return result;
 438 }
 439 
 440 /* --------------------------------------------------------------------------------------------- */
 441 
 442 static int
 443 str_8bit_term_width2 (const char *text, size_t length)
     /* [previous][next][first][last][top][bottom][index][help]  */
 444 {
 445     size_t text_len;
 446 
 447     text_len = strlen (text);
 448 
 449     return (length != (size_t) (-1)) ? MIN (text_len, length) : text_len;
 450 }
 451 
 452 /* --------------------------------------------------------------------------------------------- */
 453 
 454 static int
 455 str_8bit_term_width1 (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 456 {
 457     return str_8bit_term_width2 (text, (size_t) (-1));
 458 }
 459 
 460 /* --------------------------------------------------------------------------------------------- */
 461 
 462 static int
 463 str_8bit_term_char_width (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 464 {
 465     (void) text;
 466     return 1;
 467 }
 468 
 469 /* --------------------------------------------------------------------------------------------- */
 470 
 471 static const char *
 472 str_8bit_term_substring (const char *text, int start, int width)
     /* [previous][next][first][last][top][bottom][index][help]  */
 473 {
 474     static char result[BUF_MEDIUM];
 475     size_t remain;
 476     char *actual;
 477     size_t length;
 478 
 479     actual = result;
 480     remain = sizeof (result);
 481     length = strlen (text);
 482 
 483     if (start < (int) length)
 484     {
 485         size_t pos;
 486 
 487         for (pos = start; pos < length && width > 0 && remain > 1;
 488              pos++, width--, actual++, remain--)
 489             actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
 490     }
 491 
 492     for (; width > 0 && remain > 1; actual++, remain--, width--)
 493         actual[0] = ' ';
 494 
 495     actual[0] = '\0';
 496     return result;
 497 }
 498 
 499 /* --------------------------------------------------------------------------------------------- */
 500 
 501 static const char *
 502 str_8bit_trunc (const char *text, int width)
     /* [previous][next][first][last][top][bottom][index][help]  */
 503 {
 504     static char result[MC_MAXPATHLEN];
 505     int remain;
 506     char *actual;
 507     size_t pos = 0;
 508     size_t length;
 509 
 510     actual = result;
 511     remain = sizeof (result);
 512     length = strlen (text);
 513 
 514     if ((int) length > width)
 515     {
 516         for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--)
 517             actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
 518 
 519         if (remain <= 1)
 520             goto finally;
 521         actual[0] = '~';
 522         actual++;
 523         remain--;
 524 
 525         pos += length - width + 1;
 526         for (; pos < length && remain > 1; pos++, actual++, remain--)
 527             actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
 528     }
 529     else
 530     {
 531         for (; pos < length && remain > 1; pos++, actual++, remain--)
 532             actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
 533     }
 534 
 535 finally:
 536     actual[0] = '\0';
 537     return result;
 538 }
 539 
 540 /* --------------------------------------------------------------------------------------------- */
 541 
 542 static int
 543 str_8bit_offset_to_pos (const char *text, size_t length)
     /* [previous][next][first][last][top][bottom][index][help]  */
 544 {
 545     (void) text;
 546     return (int) length;
 547 }
 548 
 549 /* --------------------------------------------------------------------------------------------- */
 550 
 551 static int
 552 str_8bit_column_to_pos (const char *text, size_t pos)
     /* [previous][next][first][last][top][bottom][index][help]  */
 553 {
 554     (void) text;
 555     return (int) pos;
 556 }
 557 
 558 /* --------------------------------------------------------------------------------------------- */
 559 
 560 static char *
 561 str_8bit_create_search_needle (const char *needle, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 562 {
 563     (void) case_sen;
 564     return (char *) needle;
 565 }
 566 
 567 /* --------------------------------------------------------------------------------------------- */
 568 
 569 static void
 570 str_8bit_release_search_needle (char *needle, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 571 {
 572     (void) case_sen;
 573     (void) needle;
 574 }
 575 
 576 /* --------------------------------------------------------------------------------------------- */
 577 
 578 static char *
 579 str_8bit_strdown (const char *str)
     /* [previous][next][first][last][top][bottom][index][help]  */
 580 {
 581     char *rets, *p;
 582 
 583     if (str == NULL)
 584         return NULL;
 585 
 586     rets = g_strdup (str);
 587 
 588     for (p = rets; *p != '\0'; p++)
 589         *p = char_tolower (*p);
 590 
 591     return rets;
 592 }
 593 
 594 /* --------------------------------------------------------------------------------------------- */
 595 
 596 static const char *
 597 str_8bit_search_first (const char *text, const char *search, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 598 {
 599     char *fold_text;
 600     char *fold_search;
 601     const char *match;
 602 
 603     fold_text = case_sen ? (char *) text : str_8bit_strdown (text);
 604     fold_search = case_sen ? (char *) search : str_8bit_strdown (search);
 605 
 606     match = g_strstr_len (fold_text, -1, fold_search);
 607     if (match != NULL)
 608     {
 609         size_t offset;
 610 
 611         offset = match - fold_text;
 612         match = text + offset;
 613     }
 614 
 615     if (!case_sen)
 616     {
 617         g_free (fold_text);
 618         g_free (fold_search);
 619     }
 620 
 621     return match;
 622 }
 623 
 624 /* --------------------------------------------------------------------------------------------- */
 625 
 626 static const char *
 627 str_8bit_search_last (const char *text, const char *search, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 628 {
 629     char *fold_text;
 630     char *fold_search;
 631     const char *match;
 632 
 633     fold_text = case_sen ? (char *) text : str_8bit_strdown (text);
 634     fold_search = case_sen ? (char *) search : str_8bit_strdown (search);
 635 
 636     match = g_strrstr_len (fold_text, -1, fold_search);
 637     if (match != NULL)
 638     {
 639         size_t offset;
 640 
 641         offset = match - fold_text;
 642         match = text + offset;
 643     }
 644 
 645     if (!case_sen)
 646     {
 647         g_free (fold_text);
 648         g_free (fold_search);
 649     }
 650 
 651     return match;
 652 }
 653 
 654 /* --------------------------------------------------------------------------------------------- */
 655 
 656 static int
 657 str_8bit_compare (const char *t1, const char *t2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 658 {
 659     return strcmp (t1, t2);
 660 }
 661 
 662 /* --------------------------------------------------------------------------------------------- */
 663 
 664 static int
 665 str_8bit_ncompare (const char *t1, const char *t2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 666 {
 667     size_t l1, l2;
 668 
 669     l1 = strlen (t1);
 670     l2 = strlen (t2);
 671 
 672     return strncmp (t1, t2, MIN (l1, l2));
 673 }
 674 
 675 /* --------------------------------------------------------------------------------------------- */
 676 
 677 static int
 678 str_8bit_casecmp (const char *s1, const char *s2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 679 {
 680     // code from GLib
 681 
 682 #ifdef HAVE_STRCASECMP
 683     g_return_val_if_fail (s1 != NULL, 0);
 684     g_return_val_if_fail (s2 != NULL, 0);
 685 
 686     return strcasecmp (s1, s2);
 687 #else
 688 
 689     g_return_val_if_fail (s1 != NULL, 0);
 690     g_return_val_if_fail (s2 != NULL, 0);
 691 
 692     for (; *s1 != '\0' && *s2 != '\0'; s1++, s2++)
 693     {
 694         gint c1, c2;
 695 
 696         /* According to A. Cox, some platforms have islower's that
 697          * don't work right on non-uppercase
 698          */
 699         c1 = isupper ((guchar) *s1) ? tolower ((guchar) *s1) : *s1;
 700         c2 = isupper ((guchar) *s2) ? tolower ((guchar) *s2) : *s2;
 701         if (c1 != c2)
 702             return (c1 - c2);
 703     }
 704 
 705     return (((gint) (guchar) *s1) - ((gint) (guchar) *s2));
 706 #endif
 707 }
 708 
 709 /* --------------------------------------------------------------------------------------------- */
 710 
 711 static int
 712 str_8bit_ncasecmp (const char *s1, const char *s2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 713 {
 714     size_t l1, l2;
 715     size_t n;
 716 
 717     g_return_val_if_fail (s1 != NULL, 0);
 718     g_return_val_if_fail (s2 != NULL, 0);
 719 
 720     l1 = strlen (s1);
 721     l2 = strlen (s2);
 722     n = MIN (l1, l2);
 723 
 724     // code from GLib
 725 
 726 #ifdef HAVE_STRNCASECMP
 727     return strncasecmp (s1, s2, n);
 728 #else
 729 
 730     for (; *s1 != '\0' && *s2 != '\0'; s1++, s2++)
 731     {
 732         gint c1, c2;
 733 
 734         n--;
 735         /* According to A. Cox, some platforms have islower's that
 736          * don't work right on non-uppercase
 737          */
 738         c1 = isupper ((guchar) *s1) ? tolower ((guchar) *s1) : *s1;
 739         c2 = isupper ((guchar) *s2) ? tolower ((guchar) *s2) : *s2;
 740         if (c1 != c2)
 741             return (c1 - c2);
 742     }
 743 
 744     if (n == 0)
 745         return 0;
 746 
 747     return (((gint) (guchar) *s1) - ((gint) (guchar) *s2));
 748 
 749 #endif
 750 }
 751 
 752 /* --------------------------------------------------------------------------------------------- */
 753 
 754 static int
 755 str_8bit_prefix (const char *text, const char *prefix)
     /* [previous][next][first][last][top][bottom][index][help]  */
 756 {
 757     int result;
 758 
 759     for (result = 0;
 760          text[result] != '\0' && prefix[result] != '\0' && text[result] == prefix[result]; result++)
 761         ;
 762 
 763     return result;
 764 }
 765 
 766 /* --------------------------------------------------------------------------------------------- */
 767 
 768 static int
 769 str_8bit_caseprefix (const char *text, const char *prefix)
     /* [previous][next][first][last][top][bottom][index][help]  */
 770 {
 771     int result;
 772 
 773     for (result = 0; text[result] != '\0' && prefix[result] != '\0'
 774          && char_toupper (text[result]) == char_toupper (prefix[result]);
 775          result++)
 776         ;
 777 
 778     return result;
 779 }
 780 
 781 /* --------------------------------------------------------------------------------------------- */
 782 
 783 static void
 784 str_8bit_fix_string (char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 785 {
 786     (void) text;
 787 }
 788 
 789 /* --------------------------------------------------------------------------------------------- */
 790 
 791 static char *
 792 str_8bit_create_key (const char *text, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 793 {
 794     return case_sen ? (char *) text : str_8bit_strdown (text);
 795 }
 796 
 797 /* --------------------------------------------------------------------------------------------- */
 798 
 799 static int
 800 str_8bit_key_collate (const char *t1, const char *t2, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 801 {
 802     return case_sen ? strcmp (t1, t2) : strcoll (t1, t2);
 803 }
 804 
 805 /* --------------------------------------------------------------------------------------------- */
 806 
 807 static void
 808 str_8bit_release_key (char *key, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 809 {
 810     if (!case_sen)
 811         g_free (key);
 812 }
 813 
 814 /* --------------------------------------------------------------------------------------------- */
 815 /*** public functions ****************************************************************************/
 816 /* --------------------------------------------------------------------------------------------- */
 817 
 818 struct str_class
 819 str_8bit_init (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 820 {
 821     struct str_class result;
 822 
 823     result.conv_gerror_message = str_8bit_conv_gerror_message;
 824     result.vfs_convert_to = str_8bit_vfs_convert_to;
 825     result.insert_replace_char = str_8bit_insert_replace_char;
 826     result.is_valid_string = str_8bit_is_valid_string;
 827     result.is_valid_char = str_8bit_is_valid_char;
 828     result.cnext_char = str_8bit_cnext_char;
 829     result.cprev_char = str_8bit_cprev_char;
 830     result.cnext_char_safe = str_8bit_cnext_char;
 831     result.cprev_char_safe = str_8bit_cprev_char;
 832     result.cnext_noncomb_char = str_8bit_cnext_noncomb_char;
 833     result.cprev_noncomb_char = str_8bit_cprev_noncomb_char;
 834     result.char_isspace = str_8bit_isspace;
 835     result.char_ispunct = str_8bit_ispunct;
 836     result.char_isalnum = str_8bit_isalnum;
 837     result.char_isdigit = str_8bit_isdigit;
 838     result.char_isprint = str_8bit_isprint;
 839     result.char_iscombiningmark = str_8bit_iscombiningmark;
 840     result.char_toupper = str_8bit_toupper;
 841     result.char_tolower = str_8bit_tolower;
 842     result.length = str_8bit_length;
 843     result.length2 = str_8bit_length2;
 844     result.length_noncomb = str_8bit_length;
 845     result.fix_string = str_8bit_fix_string;
 846     result.term_form = str_8bit_term_form;
 847     result.fit_to_term = str_8bit_fit_to_term;
 848     result.term_trim = str_8bit_term_trim;
 849     result.term_width2 = str_8bit_term_width2;
 850     result.term_width1 = str_8bit_term_width1;
 851     result.term_char_width = str_8bit_term_char_width;
 852     result.term_substring = str_8bit_term_substring;
 853     result.trunc = str_8bit_trunc;
 854     result.offset_to_pos = str_8bit_offset_to_pos;
 855     result.column_to_pos = str_8bit_column_to_pos;
 856     result.create_search_needle = str_8bit_create_search_needle;
 857     result.release_search_needle = str_8bit_release_search_needle;
 858     result.search_first = str_8bit_search_first;
 859     result.search_last = str_8bit_search_last;
 860     result.compare = str_8bit_compare;
 861     result.ncompare = str_8bit_ncompare;
 862     result.casecmp = str_8bit_casecmp;
 863     result.ncasecmp = str_8bit_ncasecmp;
 864     result.prefix = str_8bit_prefix;
 865     result.caseprefix = str_8bit_caseprefix;
 866     result.create_key = str_8bit_create_key;
 867     result.create_key_for_filename = str_8bit_create_key;
 868     result.key_collate = str_8bit_key_collate;
 869     result.release_key = str_8bit_release_key;
 870 
 871     return result;
 872 }
 873 
 874 /* --------------------------------------------------------------------------------------------- */

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