root/lib/strutil/strutil.c

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

DEFINITIONS

This source file includes following definitions.
  1. str_test_not_convert
  2. _str_convert
  3. str_test_encoding_class
  4. str_choose_str_functions
  5. str_crt_conv_to
  6. str_crt_conv_from
  7. str_close_conv
  8. str_convert
  9. str_nconvert
  10. str_conv_gerror_message
  11. str_vfs_convert_from
  12. str_vfs_convert_to
  13. str_printf
  14. str_insert_replace_char
  15. str_translate_char
  16. str_detect_termencoding
  17. str_isutf8
  18. str_init_strings
  19. str_uninit_strings
  20. str_term_form
  21. str_fit_to_term
  22. str_term_trim
  23. str_term_substring
  24. str_get_next_char
  25. str_cget_next_char
  26. str_next_char
  27. str_cnext_char
  28. str_get_prev_char
  29. str_cget_prev_char
  30. str_prev_char
  31. str_cprev_char
  32. str_get_next_char_safe
  33. str_cget_next_char_safe
  34. str_next_char_safe
  35. str_cnext_char_safe
  36. str_get_prev_char_safe
  37. str_cget_prev_char_safe
  38. str_prev_char_safe
  39. str_cprev_char_safe
  40. str_next_noncomb_char
  41. str_cnext_noncomb_char
  42. str_prev_noncomb_char
  43. str_cprev_noncomb_char
  44. str_is_valid_char
  45. str_term_width1
  46. str_term_width2
  47. str_term_char_width
  48. str_offset_to_pos
  49. str_length
  50. str_length_char
  51. str_length2
  52. str_length_noncomb
  53. str_column_to_pos
  54. str_isspace
  55. str_ispunct
  56. str_isalnum
  57. str_isdigit
  58. str_toupper
  59. str_tolower
  60. str_isprint
  61. str_iscombiningmark
  62. str_trunc
  63. str_create_search_needle
  64. str_release_search_needle
  65. str_search_first
  66. str_search_last
  67. str_is_valid_string
  68. str_compare
  69. str_ncompare
  70. str_casecmp
  71. str_ncasecmp
  72. str_prefix
  73. str_caseprefix
  74. str_fix_string
  75. str_create_key
  76. str_create_key_for_filename
  77. str_key_collate
  78. str_release_key
  79. str_msg_term_size
  80. strrstr_skip_count
  81. parse_integer

   1 /*
   2    Common strings utilities
   3 
   4    Copyright (C) 2007-2024
   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 <http://www.gnu.org/licenses/>.
  24  */
  25 
  26 #include <config.h>
  27 
  28 #include <stdlib.h>
  29 #include <langinfo.h>
  30 #include <string.h>
  31 #include <errno.h>
  32 
  33 #include "lib/global.h"
  34 #include "lib/util.h"           /* MC_PTR_FREE */
  35 #include "lib/strutil.h"
  36 
  37 /*** global variables ****************************************************************************/
  38 
  39 GIConv str_cnv_to_term;
  40 GIConv str_cnv_from_term;
  41 GIConv str_cnv_not_convert = INVALID_CONV;
  42 
  43 /*** file scope macro definitions ****************************************************************/
  44 
  45 /*** file scope type declarations ****************************************************************/
  46 
  47 /*** forward declarations (file scope functions) *************************************************/
  48 
  49 /*** file scope variables ************************************************************************/
  50 
  51 /* names, that are used for utf-8 */
  52 static const char *const str_utf8_encodings[] = {
  53     "utf-8",
  54     "utf8",
  55     NULL
  56 };
  57 
  58 /* standard 8bit encodings, no wide or multibytes characters */
  59 static const char *const str_8bit_encodings[] = {
  60     "cp-1251",
  61     "cp1251",
  62     /* solaris */
  63     "ansi-1251",
  64     "ansi1251",
  65     "cp-1250",
  66     "cp1250",
  67     "cp-866",
  68     "cp866",
  69     /* glibc */
  70     "ibm-866",
  71     "ibm866",
  72     "cp-850",
  73     "cp850",
  74     "cp-852",
  75     "cp852",
  76     "iso-8859",
  77     "iso8859",
  78     "koi8",
  79     NULL
  80 };
  81 
  82 /* terminal encoding */
  83 static char *codeset = NULL;
  84 static char *term_encoding = NULL;
  85 /* function for encoding specific operations */
  86 static struct str_class used_class;
  87 
  88 /* --------------------------------------------------------------------------------------------- */
  89 /*** file scope functions ************************************************************************/
  90 /* --------------------------------------------------------------------------------------------- */
  91 
  92 /* if enc is same encoding like on terminal */
  93 static int
  94 str_test_not_convert (const char *enc)
     /* [previous][next][first][last][top][bottom][index][help]  */
  95 {
  96     return g_ascii_strcasecmp (enc, codeset) == 0;
  97 }
  98 
  99 /* --------------------------------------------------------------------------------------------- */
 100 
 101 static estr_t
 102 _str_convert (GIConv coder, const char *string, int size, GString *buffer)
     /* [previous][next][first][last][top][bottom][index][help]  */
 103 {
 104     estr_t state = ESTR_SUCCESS;
 105     gssize left;
 106     gsize bytes_read = 0;
 107     gsize bytes_written = 0;
 108 
 109     errno = 0;                  /* FIXME: is it really needed? */
 110 
 111     if (coder == INVALID_CONV)
 112         return ESTR_FAILURE;
 113 
 114     if (string == NULL || buffer == NULL)
 115         return ESTR_FAILURE;
 116 
 117     /*
 118        if (! used_class.is_valid_string (string))
 119        {
 120        return ESTR_FAILURE;
 121        }
 122      */
 123     if (size < 0)
 124         size = strlen (string);
 125     else
 126     {
 127         left = strlen (string);
 128         if (left < size)
 129             size = left;
 130     }
 131 
 132     left = size;
 133     g_iconv (coder, NULL, NULL, NULL, NULL);
 134 
 135     while (left != 0)
 136     {
 137         gchar *tmp_buff;
 138         GError *mcerror = NULL;
 139 
 140         tmp_buff = g_convert_with_iconv ((const gchar *) string,
 141                                          left, coder, &bytes_read, &bytes_written, &mcerror);
 142         if (mcerror != NULL)
 143         {
 144             int code = mcerror->code;
 145 
 146             g_error_free (mcerror);
 147             mcerror = NULL;
 148 
 149             switch (code)
 150             {
 151             case G_CONVERT_ERROR_NO_CONVERSION:
 152                 /* Conversion between the requested character sets is not supported. */
 153                 g_free (tmp_buff);
 154                 mc_g_string_append_c_len (buffer, '?', strlen (string));
 155                 return ESTR_FAILURE;
 156 
 157             case G_CONVERT_ERROR_ILLEGAL_SEQUENCE:
 158                 /* Invalid byte sequence in conversion input. */
 159                 if ((tmp_buff == NULL) && (bytes_read != 0))
 160                     /* recode valid byte sequence */
 161                     tmp_buff = g_convert_with_iconv ((const gchar *) string,
 162                                                      bytes_read, coder, NULL, NULL, NULL);
 163 
 164                 if (tmp_buff != NULL)
 165                 {
 166                     g_string_append (buffer, tmp_buff);
 167                     g_free (tmp_buff);
 168                 }
 169 
 170                 if ((int) bytes_read >= left)
 171                     return ESTR_PROBLEM;
 172 
 173                 string += bytes_read + 1;
 174                 size -= (bytes_read + 1);
 175                 left -= (bytes_read + 1);
 176                 g_string_append_c (buffer, *(string - 1));
 177                 state = ESTR_PROBLEM;
 178                 break;
 179 
 180             case G_CONVERT_ERROR_PARTIAL_INPUT:
 181                 /* Partial character sequence at end of input. */
 182                 g_string_append (buffer, tmp_buff);
 183                 g_free (tmp_buff);
 184                 if ((int) bytes_read < left)
 185                     mc_g_string_append_c_len (buffer, '?', left - bytes_read);
 186                 return ESTR_PROBLEM;
 187 
 188             case G_CONVERT_ERROR_BAD_URI:      /* Don't know how handle this error :( */
 189             case G_CONVERT_ERROR_NOT_ABSOLUTE_PATH:    /* Don't know how handle this error :( */
 190             case G_CONVERT_ERROR_FAILED:       /* Conversion failed for some reason. */
 191             default:
 192                 g_free (tmp_buff);
 193                 return ESTR_FAILURE;
 194             }
 195         }
 196         else if (tmp_buff == NULL)
 197         {
 198             g_string_append (buffer, string);
 199             return ESTR_PROBLEM;
 200         }
 201         else if (*tmp_buff == '\0')
 202         {
 203             g_free (tmp_buff);
 204             g_string_append (buffer, string);
 205             return state;
 206         }
 207         else
 208         {
 209             g_string_append (buffer, tmp_buff);
 210             g_free (tmp_buff);
 211             string += bytes_read;
 212             left -= bytes_read;
 213         }
 214     }
 215 
 216     return state;
 217 }
 218 
 219 /* --------------------------------------------------------------------------------------------- */
 220 
 221 static int
 222 str_test_encoding_class (const char *encoding, const char *const *table)
     /* [previous][next][first][last][top][bottom][index][help]  */
 223 {
 224     int result = 0;
 225 
 226     if (encoding != NULL)
 227     {
 228         int t;
 229 
 230         for (t = 0; table[t] != NULL; t++)
 231             if (g_ascii_strncasecmp (encoding, table[t], strlen (table[t])) == 0)
 232                 result++;
 233     }
 234 
 235     return result;
 236 }
 237 
 238 /* --------------------------------------------------------------------------------------------- */
 239 
 240 static void
 241 str_choose_str_functions (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 242 {
 243     if (str_test_encoding_class (codeset, str_utf8_encodings))
 244         used_class = str_utf8_init ();
 245     else if (str_test_encoding_class (codeset, str_8bit_encodings))
 246         used_class = str_8bit_init ();
 247     else
 248         used_class = str_ascii_init ();
 249 }
 250 
 251 /* --------------------------------------------------------------------------------------------- */
 252 /*** public functions ****************************************************************************/
 253 /* --------------------------------------------------------------------------------------------- */
 254 
 255 GIConv
 256 str_crt_conv_to (const char *to_enc)
     /* [previous][next][first][last][top][bottom][index][help]  */
 257 {
 258     return (!str_test_not_convert (to_enc)) ? g_iconv_open (to_enc, codeset) : str_cnv_not_convert;
 259 }
 260 
 261 /* --------------------------------------------------------------------------------------------- */
 262 
 263 GIConv
 264 str_crt_conv_from (const char *from_enc)
     /* [previous][next][first][last][top][bottom][index][help]  */
 265 {
 266     return (!str_test_not_convert (from_enc))
 267         ? g_iconv_open (codeset, from_enc) : str_cnv_not_convert;
 268 }
 269 
 270 /* --------------------------------------------------------------------------------------------- */
 271 
 272 void
 273 str_close_conv (GIConv conv)
     /* [previous][next][first][last][top][bottom][index][help]  */
 274 {
 275     if (conv != INVALID_CONV && conv != str_cnv_not_convert)
 276         g_iconv_close (conv);
 277 }
 278 
 279 /* --------------------------------------------------------------------------------------------- */
 280 
 281 estr_t
 282 str_convert (GIConv coder, const char *string, GString *buffer)
     /* [previous][next][first][last][top][bottom][index][help]  */
 283 {
 284     return _str_convert (coder, string, -1, buffer);
 285 }
 286 
 287 /* --------------------------------------------------------------------------------------------- */
 288 
 289 estr_t
 290 str_nconvert (GIConv coder, const char *string, int size, GString *buffer)
     /* [previous][next][first][last][top][bottom][index][help]  */
 291 {
 292     return _str_convert (coder, string, size, buffer);
 293 }
 294 
 295 /* --------------------------------------------------------------------------------------------- */
 296 
 297 gchar *
 298 str_conv_gerror_message (GError *mcerror, const char *def_msg)
     /* [previous][next][first][last][top][bottom][index][help]  */
 299 {
 300     return used_class.conv_gerror_message (mcerror, def_msg);
 301 }
 302 
 303 /* --------------------------------------------------------------------------------------------- */
 304 
 305 estr_t
 306 str_vfs_convert_from (GIConv coder, const char *string, GString *buffer)
     /* [previous][next][first][last][top][bottom][index][help]  */
 307 {
 308     estr_t result = ESTR_SUCCESS;
 309 
 310     if (coder == str_cnv_not_convert)
 311         g_string_append (buffer, string != NULL ? string : "");
 312     else
 313         result = _str_convert (coder, string, -1, buffer);
 314 
 315     return result;
 316 }
 317 
 318 /* --------------------------------------------------------------------------------------------- */
 319 
 320 estr_t
 321 str_vfs_convert_to (GIConv coder, const char *string, int size, GString *buffer)
     /* [previous][next][first][last][top][bottom][index][help]  */
 322 {
 323     return used_class.vfs_convert_to (coder, string, size, buffer);
 324 }
 325 
 326 /* --------------------------------------------------------------------------------------------- */
 327 
 328 void
 329 str_printf (GString *buffer, const char *format, ...)
     /* [previous][next][first][last][top][bottom][index][help]  */
 330 {
 331     va_list ap;
 332     va_start (ap, format);
 333 
 334     g_string_append_vprintf (buffer, format, ap);
 335     va_end (ap);
 336 }
 337 
 338 /* --------------------------------------------------------------------------------------------- */
 339 
 340 void
 341 str_insert_replace_char (GString *buffer)
     /* [previous][next][first][last][top][bottom][index][help]  */
 342 {
 343     used_class.insert_replace_char (buffer);
 344 }
 345 
 346 /* --------------------------------------------------------------------------------------------- */
 347 
 348 estr_t
 349 str_translate_char (GIConv conv, const char *keys, size_t ch_size, char *output, size_t out_size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 350 {
 351     size_t left;
 352     size_t cnv;
 353 
 354     g_iconv (conv, NULL, NULL, NULL, NULL);
 355 
 356     left = (ch_size == (size_t) (-1)) ? strlen (keys) : ch_size;
 357 
 358     cnv = g_iconv (conv, (gchar **) & keys, &left, &output, &out_size);
 359     if (cnv == (size_t) (-1))
 360         return (errno == EINVAL) ? ESTR_PROBLEM : ESTR_FAILURE;
 361 
 362     output[0] = '\0';
 363     return ESTR_SUCCESS;
 364 }
 365 
 366 /* --------------------------------------------------------------------------------------------- */
 367 
 368 const char *
 369 str_detect_termencoding (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 370 {
 371     if (term_encoding == NULL)
 372     {
 373         /* On Linux, nl_langinfo (CODESET) returns upper case UTF-8 whether the LANG is set
 374            to utf-8 or UTF-8.
 375            On Mac OS X, it returns the same case as the LANG input.
 376            So let transform result of nl_langinfo (CODESET) to upper case  unconditionally. */
 377         term_encoding = g_ascii_strup (nl_langinfo (CODESET), -1);
 378     }
 379 
 380     return term_encoding;
 381 }
 382 
 383 /* --------------------------------------------------------------------------------------------- */
 384 
 385 gboolean
 386 str_isutf8 (const char *codeset_name)
     /* [previous][next][first][last][top][bottom][index][help]  */
 387 {
 388     return (str_test_encoding_class (codeset_name, str_utf8_encodings) != 0);
 389 }
 390 
 391 /* --------------------------------------------------------------------------------------------- */
 392 
 393 void
 394 str_init_strings (const char *termenc)
     /* [previous][next][first][last][top][bottom][index][help]  */
 395 {
 396     codeset = termenc != NULL ? g_ascii_strup (termenc, -1) : g_strdup (str_detect_termencoding ());
 397 
 398     str_cnv_not_convert = g_iconv_open (codeset, codeset);
 399     if (str_cnv_not_convert == INVALID_CONV)
 400     {
 401         if (termenc != NULL)
 402         {
 403             g_free (codeset);
 404             codeset = g_strdup (str_detect_termencoding ());
 405             str_cnv_not_convert = g_iconv_open (codeset, codeset);
 406         }
 407 
 408         if (str_cnv_not_convert == INVALID_CONV)
 409         {
 410             g_free (codeset);
 411             codeset = g_strdup (DEFAULT_CHARSET);
 412             str_cnv_not_convert = g_iconv_open (codeset, codeset);
 413         }
 414     }
 415 
 416     str_cnv_to_term = str_cnv_not_convert;
 417     str_cnv_from_term = str_cnv_not_convert;
 418 
 419     str_choose_str_functions ();
 420 }
 421 
 422 /* --------------------------------------------------------------------------------------------- */
 423 
 424 void
 425 str_uninit_strings (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 426 {
 427     if (str_cnv_not_convert != INVALID_CONV)
 428         g_iconv_close (str_cnv_not_convert);
 429     /* NULL-ize pointers to avoid double free in unit tests */
 430     MC_PTR_FREE (term_encoding);
 431     MC_PTR_FREE (codeset);
 432 }
 433 
 434 /* --------------------------------------------------------------------------------------------- */
 435 
 436 const char *
 437 str_term_form (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 438 {
 439     return used_class.term_form (text);
 440 }
 441 
 442 /* --------------------------------------------------------------------------------------------- */
 443 
 444 const char *
 445 str_fit_to_term (const char *text, int width, align_crt_t just_mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 446 {
 447     return used_class.fit_to_term (text, width, just_mode);
 448 }
 449 
 450 /* --------------------------------------------------------------------------------------------- */
 451 
 452 const char *
 453 str_term_trim (const char *text, int width)
     /* [previous][next][first][last][top][bottom][index][help]  */
 454 {
 455     return used_class.term_trim (text, width);
 456 }
 457 
 458 /* --------------------------------------------------------------------------------------------- */
 459 
 460 const char *
 461 str_term_substring (const char *text, int start, int width)
     /* [previous][next][first][last][top][bottom][index][help]  */
 462 {
 463     return used_class.term_substring (text, start, width);
 464 }
 465 
 466 /* --------------------------------------------------------------------------------------------- */
 467 
 468 char *
 469 str_get_next_char (char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 470 {
 471 
 472     used_class.cnext_char ((const char **) &text);
 473     return text;
 474 }
 475 
 476 /* --------------------------------------------------------------------------------------------- */
 477 
 478 const char *
 479 str_cget_next_char (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 480 {
 481     used_class.cnext_char (&text);
 482     return text;
 483 }
 484 
 485 /* --------------------------------------------------------------------------------------------- */
 486 
 487 void
 488 str_next_char (char **text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 489 {
 490     used_class.cnext_char ((const char **) text);
 491 }
 492 
 493 /* --------------------------------------------------------------------------------------------- */
 494 
 495 void
 496 str_cnext_char (const char **text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 497 {
 498     used_class.cnext_char (text);
 499 }
 500 
 501 /* --------------------------------------------------------------------------------------------- */
 502 
 503 char *
 504 str_get_prev_char (char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 505 {
 506     used_class.cprev_char ((const char **) &text);
 507     return text;
 508 }
 509 
 510 /* --------------------------------------------------------------------------------------------- */
 511 
 512 const char *
 513 str_cget_prev_char (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 514 {
 515     used_class.cprev_char (&text);
 516     return text;
 517 }
 518 
 519 /* --------------------------------------------------------------------------------------------- */
 520 
 521 void
 522 str_prev_char (char **text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 523 {
 524     used_class.cprev_char ((const char **) text);
 525 }
 526 
 527 /* --------------------------------------------------------------------------------------------- */
 528 
 529 void
 530 str_cprev_char (const char **text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 531 {
 532     used_class.cprev_char (text);
 533 }
 534 
 535 /* --------------------------------------------------------------------------------------------- */
 536 
 537 char *
 538 str_get_next_char_safe (char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 539 {
 540     used_class.cnext_char_safe ((const char **) &text);
 541     return text;
 542 }
 543 
 544 /* --------------------------------------------------------------------------------------------- */
 545 
 546 const char *
 547 str_cget_next_char_safe (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 548 {
 549     used_class.cnext_char_safe (&text);
 550     return text;
 551 }
 552 
 553 /* --------------------------------------------------------------------------------------------- */
 554 
 555 void
 556 str_next_char_safe (char **text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 557 {
 558     used_class.cnext_char_safe ((const char **) text);
 559 }
 560 
 561 /* --------------------------------------------------------------------------------------------- */
 562 
 563 void
 564 str_cnext_char_safe (const char **text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 565 {
 566     used_class.cnext_char_safe (text);
 567 }
 568 
 569 /* --------------------------------------------------------------------------------------------- */
 570 
 571 char *
 572 str_get_prev_char_safe (char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 573 {
 574     used_class.cprev_char_safe ((const char **) &text);
 575     return text;
 576 }
 577 
 578 /* --------------------------------------------------------------------------------------------- */
 579 
 580 const char *
 581 str_cget_prev_char_safe (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 582 {
 583     used_class.cprev_char_safe (&text);
 584     return text;
 585 }
 586 
 587 /* --------------------------------------------------------------------------------------------- */
 588 
 589 void
 590 str_prev_char_safe (char **text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 591 {
 592     used_class.cprev_char_safe ((const char **) text);
 593 }
 594 
 595 /* --------------------------------------------------------------------------------------------- */
 596 
 597 void
 598 str_cprev_char_safe (const char **text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 599 {
 600     used_class.cprev_char_safe (text);
 601 }
 602 
 603 /* --------------------------------------------------------------------------------------------- */
 604 
 605 int
 606 str_next_noncomb_char (char **text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 607 {
 608     return used_class.cnext_noncomb_char ((const char **) text);
 609 }
 610 
 611 /* --------------------------------------------------------------------------------------------- */
 612 
 613 int
 614 str_cnext_noncomb_char (const char **text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 615 {
 616     return used_class.cnext_noncomb_char (text);
 617 }
 618 
 619 /* --------------------------------------------------------------------------------------------- */
 620 
 621 int
 622 str_prev_noncomb_char (char **text, const char *begin)
     /* [previous][next][first][last][top][bottom][index][help]  */
 623 {
 624     return used_class.cprev_noncomb_char ((const char **) text, begin);
 625 }
 626 
 627 /* --------------------------------------------------------------------------------------------- */
 628 
 629 int
 630 str_cprev_noncomb_char (const char **text, const char *begin)
     /* [previous][next][first][last][top][bottom][index][help]  */
 631 {
 632     return used_class.cprev_noncomb_char (text, begin);
 633 }
 634 
 635 /* --------------------------------------------------------------------------------------------- */
 636 
 637 int
 638 str_is_valid_char (const char *ch, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 639 {
 640     return used_class.is_valid_char (ch, size);
 641 }
 642 
 643 /* --------------------------------------------------------------------------------------------- */
 644 
 645 int
 646 str_term_width1 (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 647 {
 648     return used_class.term_width1 (text);
 649 }
 650 
 651 /* --------------------------------------------------------------------------------------------- */
 652 
 653 int
 654 str_term_width2 (const char *text, size_t length)
     /* [previous][next][first][last][top][bottom][index][help]  */
 655 {
 656     return used_class.term_width2 (text, length);
 657 }
 658 
 659 /* --------------------------------------------------------------------------------------------- */
 660 
 661 int
 662 str_term_char_width (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 663 {
 664     return used_class.term_char_width (text);
 665 }
 666 
 667 /* --------------------------------------------------------------------------------------------- */
 668 
 669 int
 670 str_offset_to_pos (const char *text, size_t length)
     /* [previous][next][first][last][top][bottom][index][help]  */
 671 {
 672     return used_class.offset_to_pos (text, length);
 673 }
 674 
 675 /* --------------------------------------------------------------------------------------------- */
 676 
 677 int
 678 str_length (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 679 {
 680     return used_class.length (text);
 681 }
 682 
 683 /* --------------------------------------------------------------------------------------------- */
 684 
 685 int
 686 str_length_char (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 687 {
 688     return str_cget_next_char_safe (text) - text;
 689 }
 690 
 691 /* --------------------------------------------------------------------------------------------- */
 692 
 693 int
 694 str_length2 (const char *text, int size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 695 {
 696     return used_class.length2 (text, size);
 697 }
 698 
 699 /* --------------------------------------------------------------------------------------------- */
 700 
 701 int
 702 str_length_noncomb (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 703 {
 704     return used_class.length_noncomb (text);
 705 }
 706 
 707 /* --------------------------------------------------------------------------------------------- */
 708 
 709 int
 710 str_column_to_pos (const char *text, size_t pos)
     /* [previous][next][first][last][top][bottom][index][help]  */
 711 {
 712     return used_class.column_to_pos (text, pos);
 713 }
 714 
 715 /* --------------------------------------------------------------------------------------------- */
 716 
 717 gboolean
 718 str_isspace (const char *ch)
     /* [previous][next][first][last][top][bottom][index][help]  */
 719 {
 720     return used_class.char_isspace (ch);
 721 }
 722 
 723 /* --------------------------------------------------------------------------------------------- */
 724 
 725 gboolean
 726 str_ispunct (const char *ch)
     /* [previous][next][first][last][top][bottom][index][help]  */
 727 {
 728     return used_class.char_ispunct (ch);
 729 }
 730 
 731 /* --------------------------------------------------------------------------------------------- */
 732 
 733 gboolean
 734 str_isalnum (const char *ch)
     /* [previous][next][first][last][top][bottom][index][help]  */
 735 {
 736     return used_class.char_isalnum (ch);
 737 }
 738 
 739 /* --------------------------------------------------------------------------------------------- */
 740 
 741 gboolean
 742 str_isdigit (const char *ch)
     /* [previous][next][first][last][top][bottom][index][help]  */
 743 {
 744     return used_class.char_isdigit (ch);
 745 }
 746 
 747 /* --------------------------------------------------------------------------------------------- */
 748 
 749 gboolean
 750 str_toupper (const char *ch, char **out, size_t *remain)
     /* [previous][next][first][last][top][bottom][index][help]  */
 751 {
 752     return used_class.char_toupper (ch, out, remain);
 753 }
 754 
 755 /* --------------------------------------------------------------------------------------------- */
 756 
 757 gboolean
 758 str_tolower (const char *ch, char **out, size_t *remain)
     /* [previous][next][first][last][top][bottom][index][help]  */
 759 {
 760     return used_class.char_tolower (ch, out, remain);
 761 }
 762 
 763 /* --------------------------------------------------------------------------------------------- */
 764 
 765 gboolean
 766 str_isprint (const char *ch)
     /* [previous][next][first][last][top][bottom][index][help]  */
 767 {
 768     return used_class.char_isprint (ch);
 769 }
 770 
 771 /* --------------------------------------------------------------------------------------------- */
 772 
 773 gboolean
 774 str_iscombiningmark (const char *ch)
     /* [previous][next][first][last][top][bottom][index][help]  */
 775 {
 776     return used_class.char_iscombiningmark (ch);
 777 }
 778 
 779 /* --------------------------------------------------------------------------------------------- */
 780 
 781 const char *
 782 str_trunc (const char *text, int width)
     /* [previous][next][first][last][top][bottom][index][help]  */
 783 {
 784     return used_class.trunc (text, width);
 785 }
 786 
 787 /* --------------------------------------------------------------------------------------------- */
 788 
 789 char *
 790 str_create_search_needle (const char *needle, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 791 {
 792     return used_class.create_search_needle (needle, case_sen);
 793 }
 794 
 795 /* --------------------------------------------------------------------------------------------- */
 796 
 797 void
 798 str_release_search_needle (char *needle, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 799 {
 800     used_class.release_search_needle (needle, case_sen);
 801 }
 802 
 803 /* --------------------------------------------------------------------------------------------- */
 804 
 805 const char *
 806 str_search_first (const char *text, const char *search, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 807 {
 808     return used_class.search_first (text, search, case_sen);
 809 }
 810 
 811 /* --------------------------------------------------------------------------------------------- */
 812 
 813 const char *
 814 str_search_last (const char *text, const char *search, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 815 {
 816     return used_class.search_last (text, search, case_sen);
 817 }
 818 
 819 /* --------------------------------------------------------------------------------------------- */
 820 
 821 gboolean
 822 str_is_valid_string (const char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 823 {
 824     return used_class.is_valid_string (text);
 825 }
 826 
 827 /* --------------------------------------------------------------------------------------------- */
 828 
 829 int
 830 str_compare (const char *t1, const char *t2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 831 {
 832     return used_class.compare (t1, t2);
 833 }
 834 
 835 /* --------------------------------------------------------------------------------------------- */
 836 
 837 int
 838 str_ncompare (const char *t1, const char *t2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 839 {
 840     return used_class.ncompare (t1, t2);
 841 }
 842 
 843 /* --------------------------------------------------------------------------------------------- */
 844 
 845 int
 846 str_casecmp (const char *t1, const char *t2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 847 {
 848     return used_class.casecmp (t1, t2);
 849 }
 850 
 851 /* --------------------------------------------------------------------------------------------- */
 852 
 853 int
 854 str_ncasecmp (const char *t1, const char *t2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 855 {
 856     return used_class.ncasecmp (t1, t2);
 857 }
 858 
 859 /* --------------------------------------------------------------------------------------------- */
 860 
 861 int
 862 str_prefix (const char *text, const char *prefix)
     /* [previous][next][first][last][top][bottom][index][help]  */
 863 {
 864     return used_class.prefix (text, prefix);
 865 }
 866 
 867 /* --------------------------------------------------------------------------------------------- */
 868 
 869 int
 870 str_caseprefix (const char *text, const char *prefix)
     /* [previous][next][first][last][top][bottom][index][help]  */
 871 {
 872     return used_class.caseprefix (text, prefix);
 873 }
 874 
 875 /* --------------------------------------------------------------------------------------------- */
 876 
 877 void
 878 str_fix_string (char *text)
     /* [previous][next][first][last][top][bottom][index][help]  */
 879 {
 880     used_class.fix_string (text);
 881 }
 882 
 883 /* --------------------------------------------------------------------------------------------- */
 884 
 885 char *
 886 str_create_key (const char *text, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 887 {
 888     return used_class.create_key (text, case_sen);
 889 }
 890 
 891 /* --------------------------------------------------------------------------------------------- */
 892 
 893 char *
 894 str_create_key_for_filename (const char *text, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 895 {
 896     return used_class.create_key_for_filename (text, case_sen);
 897 }
 898 
 899 /* --------------------------------------------------------------------------------------------- */
 900 
 901 int
 902 str_key_collate (const char *t1, const char *t2, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 903 {
 904     return used_class.key_collate (t1, t2, case_sen);
 905 }
 906 
 907 /* --------------------------------------------------------------------------------------------- */
 908 
 909 void
 910 str_release_key (char *key, gboolean case_sen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 911 {
 912     used_class.release_key (key, case_sen);
 913 }
 914 
 915 /* --------------------------------------------------------------------------------------------- */
 916 
 917 void
 918 str_msg_term_size (const char *text, int *lines, int *columns)
     /* [previous][next][first][last][top][bottom][index][help]  */
 919 {
 920     char *p, *tmp;
 921     char *q;
 922     char c = '\0';
 923 
 924     *lines = 1;
 925     *columns = 0;
 926 
 927     tmp = g_strdup (text);
 928     p = tmp;
 929 
 930     while (TRUE)
 931     {
 932         int width;
 933 
 934         q = strchr (p, '\n');
 935         if (q != NULL)
 936         {
 937             c = q[0];
 938             q[0] = '\0';
 939         }
 940 
 941         width = str_term_width1 (p);
 942         if (width > *columns)
 943             *columns = width;
 944 
 945         if (q == NULL)
 946             break;
 947 
 948         q[0] = c;
 949         p = q + 1;
 950         (*lines)++;
 951     }
 952 
 953     g_free (tmp);
 954 }
 955 
 956 /* --------------------------------------------------------------------------------------------- */
 957 
 958 char *
 959 strrstr_skip_count (const char *haystack, const char *needle, size_t skip_count)
     /* [previous][next][first][last][top][bottom][index][help]  */
 960 {
 961     char *semi;
 962     ssize_t len;
 963 
 964     len = strlen (haystack);
 965 
 966     do
 967     {
 968         semi = g_strrstr_len (haystack, len, needle);
 969         if (semi == NULL)
 970             return NULL;
 971         len = semi - haystack - 1;
 972     }
 973     while (skip_count-- != 0);
 974 
 975     return semi;
 976 }
 977 
 978 /* --------------------------------------------------------------------------------------------- */
 979 /* Interpret string as a non-negative decimal integer, optionally multiplied by various values.
 980  *
 981  * @param str input value
 982  * @param invalid set to TRUE if "str" does not represent a number in this format
 983  *
 984  * @return non-negative integer representation of "str", 0 in case of error.
 985  */
 986 
 987 uintmax_t
 988 parse_integer (const char *str, gboolean *invalid)
     /* [previous][next][first][last][top][bottom][index][help]  */
 989 {
 990     uintmax_t n;
 991     char *suffix;
 992     strtol_error_t e;
 993 
 994     e = xstrtoumax (str, &suffix, 10, &n, "bcEGkKMPTwYZ0");
 995     if (e == LONGINT_INVALID_SUFFIX_CHAR && *suffix == 'x')
 996     {
 997         uintmax_t multiplier;
 998 
 999         multiplier = parse_integer (suffix + 1, invalid);
1000         if (multiplier != 0 && n * multiplier / multiplier != n)
1001         {
1002             *invalid = TRUE;
1003             return 0;
1004         }
1005 
1006         n *= multiplier;
1007     }
1008     else if (e != LONGINT_OK)
1009     {
1010         *invalid = TRUE;
1011         n = 0;
1012     }
1013 
1014     return n;
1015 }
1016 
1017 /* --------------------------------------------------------------------------------------------- */

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