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

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