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

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