strutil.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. /*
  2. Common strings utilities
  3. Copyright (C) 2007-2016
  4. Free Software Foundation, Inc.
  5. Written by:
  6. Rostislav Benes, 2007
  7. This file is part of the Midnight Commander.
  8. The Midnight Commander is free software: you can redistribute it
  9. and/or modify it under the terms of the GNU General Public License as
  10. published by the Free Software Foundation, either version 3 of the License,
  11. or (at your option) any later version.
  12. The Midnight Commander is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <config.h>
  20. #include <stdlib.h>
  21. #include <langinfo.h>
  22. #include <string.h>
  23. #include <errno.h>
  24. #include "lib/global.h"
  25. #include "lib/strutil.h"
  26. /*** global variables ****************************************************************************/
  27. GIConv str_cnv_to_term;
  28. GIConv str_cnv_from_term;
  29. GIConv str_cnv_not_convert = INVALID_CONV;
  30. /*** file scope macro definitions ****************************************************************/
  31. /*** file scope type declarations ****************************************************************/
  32. /*** file scope variables ************************************************************************/
  33. /* names, that are used for utf-8 */
  34. static const char *str_utf8_encodings[] = {
  35. "utf-8",
  36. "utf8",
  37. NULL
  38. };
  39. /* standard 8bit encodings, no wide or multibytes characters */
  40. static const char *str_8bit_encodings[] = {
  41. "cp-1251",
  42. "cp1251",
  43. "cp-1250",
  44. "cp1250",
  45. "cp-866",
  46. "cp866",
  47. "ibm-866",
  48. "ibm866",
  49. "cp-850",
  50. "cp850",
  51. "cp-852",
  52. "cp852",
  53. "iso-8859",
  54. "iso8859",
  55. "koi8",
  56. NULL
  57. };
  58. /* terminal encoding */
  59. static char *codeset = NULL;
  60. static char *term_encoding = NULL;
  61. /* function for encoding specific operations */
  62. static struct str_class used_class;
  63. /* --------------------------------------------------------------------------------------------- */
  64. /*** file scope functions ************************************************************************/
  65. /* --------------------------------------------------------------------------------------------- */
  66. /* if enc is same encoding like on terminal */
  67. static int
  68. str_test_not_convert (const char *enc)
  69. {
  70. return g_ascii_strcasecmp (enc, codeset) == 0;
  71. }
  72. /* --------------------------------------------------------------------------------------------- */
  73. static estr_t
  74. _str_convert (GIConv coder, const char *string, int size, GString * buffer)
  75. {
  76. estr_t state = ESTR_SUCCESS;
  77. gssize left;
  78. gsize bytes_read = 0;
  79. gsize bytes_written = 0;
  80. errno = 0; /* FIXME: is it really needed? */
  81. if (coder == INVALID_CONV)
  82. return ESTR_FAILURE;
  83. if (string == NULL || buffer == NULL)
  84. return ESTR_FAILURE;
  85. /*
  86. if (! used_class.is_valid_string (string))
  87. {
  88. return ESTR_FAILURE;
  89. }
  90. */
  91. if (size < 0)
  92. size = strlen (string);
  93. else
  94. {
  95. left = strlen (string);
  96. if (left < size)
  97. size = left;
  98. }
  99. left = size;
  100. g_iconv (coder, NULL, NULL, NULL, NULL);
  101. while (left != 0)
  102. {
  103. gchar *tmp_buff;
  104. GError *mcerror = NULL;
  105. tmp_buff = g_convert_with_iconv ((const gchar *) string,
  106. left, coder, &bytes_read, &bytes_written, &mcerror);
  107. if (mcerror != NULL)
  108. {
  109. int code = mcerror->code;
  110. g_error_free (mcerror);
  111. mcerror = NULL;
  112. switch (code)
  113. {
  114. case G_CONVERT_ERROR_NO_CONVERSION:
  115. /* Conversion between the requested character sets is not supported. */
  116. tmp_buff = g_strnfill (strlen (string), '?');
  117. g_string_append (buffer, tmp_buff);
  118. g_free (tmp_buff);
  119. return ESTR_FAILURE;
  120. case G_CONVERT_ERROR_ILLEGAL_SEQUENCE:
  121. /* Invalid byte sequence in conversion input. */
  122. if ((tmp_buff == NULL) && (bytes_read != 0))
  123. /* recode valid byte sequence */
  124. tmp_buff = g_convert_with_iconv ((const gchar *) string,
  125. bytes_read, coder, NULL, NULL, NULL);
  126. if (tmp_buff != NULL)
  127. {
  128. g_string_append (buffer, tmp_buff);
  129. g_free (tmp_buff);
  130. }
  131. if ((int) bytes_read >= left)
  132. return ESTR_PROBLEM;
  133. string += bytes_read + 1;
  134. size -= (bytes_read + 1);
  135. left -= (bytes_read + 1);
  136. g_string_append_c (buffer, *(string - 1));
  137. state = ESTR_PROBLEM;
  138. break;
  139. case G_CONVERT_ERROR_PARTIAL_INPUT:
  140. /* Partial character sequence at end of input. */
  141. g_string_append (buffer, tmp_buff);
  142. g_free (tmp_buff);
  143. if ((int) bytes_read < left)
  144. {
  145. left = left - bytes_read;
  146. tmp_buff = g_strnfill (left, '?');
  147. g_string_append (buffer, tmp_buff);
  148. g_free (tmp_buff);
  149. }
  150. return ESTR_PROBLEM;
  151. case G_CONVERT_ERROR_BAD_URI: /* Don't know how handle this error :( */
  152. case G_CONVERT_ERROR_NOT_ABSOLUTE_PATH: /* Don't know how handle this error :( */
  153. case G_CONVERT_ERROR_FAILED: /* Conversion failed for some reason. */
  154. default:
  155. g_free (tmp_buff);
  156. return ESTR_FAILURE;
  157. }
  158. }
  159. else if (tmp_buff == NULL)
  160. {
  161. g_string_append (buffer, string);
  162. return ESTR_PROBLEM;
  163. }
  164. else if (*tmp_buff == '\0')
  165. {
  166. g_free (tmp_buff);
  167. g_string_append (buffer, string);
  168. return state;
  169. }
  170. else
  171. {
  172. g_string_append (buffer, tmp_buff);
  173. g_free (tmp_buff);
  174. string += bytes_read;
  175. left -= bytes_read;
  176. }
  177. }
  178. return state;
  179. }
  180. /* --------------------------------------------------------------------------------------------- */
  181. static int
  182. str_test_encoding_class (const char *encoding, const char **table)
  183. {
  184. int result = 0;
  185. if (encoding != NULL)
  186. {
  187. int t;
  188. for (t = 0; table[t] != NULL; t++)
  189. if (g_ascii_strncasecmp (encoding, table[t], strlen (table[t])) == 0)
  190. result++;
  191. }
  192. return result;
  193. }
  194. /* --------------------------------------------------------------------------------------------- */
  195. static void
  196. str_choose_str_functions (void)
  197. {
  198. if (str_test_encoding_class (codeset, str_utf8_encodings))
  199. used_class = str_utf8_init ();
  200. else if (str_test_encoding_class (codeset, str_8bit_encodings))
  201. used_class = str_8bit_init ();
  202. else
  203. used_class = str_ascii_init ();
  204. }
  205. /* --------------------------------------------------------------------------------------------- */
  206. /*** public functions ****************************************************************************/
  207. /* --------------------------------------------------------------------------------------------- */
  208. GIConv
  209. str_crt_conv_to (const char *to_enc)
  210. {
  211. return (!str_test_not_convert (to_enc)) ? g_iconv_open (to_enc, codeset) : str_cnv_not_convert;
  212. }
  213. /* --------------------------------------------------------------------------------------------- */
  214. GIConv
  215. str_crt_conv_from (const char *from_enc)
  216. {
  217. return (!str_test_not_convert (from_enc))
  218. ? g_iconv_open (codeset, from_enc) : str_cnv_not_convert;
  219. }
  220. /* --------------------------------------------------------------------------------------------- */
  221. void
  222. str_close_conv (GIConv conv)
  223. {
  224. if (conv != str_cnv_not_convert)
  225. g_iconv_close (conv);
  226. }
  227. /* --------------------------------------------------------------------------------------------- */
  228. estr_t
  229. str_convert (GIConv coder, const char *string, GString * buffer)
  230. {
  231. return _str_convert (coder, string, -1, buffer);
  232. }
  233. /* --------------------------------------------------------------------------------------------- */
  234. estr_t
  235. str_nconvert (GIConv coder, const char *string, int size, GString * buffer)
  236. {
  237. return _str_convert (coder, string, size, buffer);
  238. }
  239. /* --------------------------------------------------------------------------------------------- */
  240. gchar *
  241. str_conv_gerror_message (GError * mcerror, const char *def_msg)
  242. {
  243. return used_class.conv_gerror_message (mcerror, def_msg);
  244. }
  245. /* --------------------------------------------------------------------------------------------- */
  246. estr_t
  247. str_vfs_convert_from (GIConv coder, const char *string, GString * buffer)
  248. {
  249. estr_t result = ESTR_SUCCESS;
  250. if (coder == str_cnv_not_convert)
  251. g_string_append (buffer, string != NULL ? string : "");
  252. else
  253. result = _str_convert (coder, string, -1, buffer);
  254. return result;
  255. }
  256. /* --------------------------------------------------------------------------------------------- */
  257. estr_t
  258. str_vfs_convert_to (GIConv coder, const char *string, int size, GString * buffer)
  259. {
  260. return used_class.vfs_convert_to (coder, string, size, buffer);
  261. }
  262. /* --------------------------------------------------------------------------------------------- */
  263. void
  264. str_printf (GString * buffer, const char *format, ...)
  265. {
  266. va_list ap;
  267. va_start (ap, format);
  268. g_string_append_vprintf (buffer, format, ap);
  269. va_end (ap);
  270. }
  271. /* --------------------------------------------------------------------------------------------- */
  272. void
  273. str_insert_replace_char (GString * buffer)
  274. {
  275. used_class.insert_replace_char (buffer);
  276. }
  277. /* --------------------------------------------------------------------------------------------- */
  278. estr_t
  279. str_translate_char (GIConv conv, const char *keys, size_t ch_size, char *output, size_t out_size)
  280. {
  281. size_t left;
  282. size_t cnv;
  283. g_iconv (conv, NULL, NULL, NULL, NULL);
  284. left = (ch_size == (size_t) (-1)) ? strlen (keys) : ch_size;
  285. cnv = g_iconv (conv, (gchar **) & keys, &left, &output, &out_size);
  286. if (cnv == (size_t) (-1))
  287. return (errno == EINVAL) ? ESTR_PROBLEM : ESTR_FAILURE;
  288. output[0] = '\0';
  289. return ESTR_SUCCESS;
  290. }
  291. /* --------------------------------------------------------------------------------------------- */
  292. const char *
  293. str_detect_termencoding (void)
  294. {
  295. if (term_encoding == NULL)
  296. {
  297. /* On Linux, nl_langinfo (CODESET) returns upper case UTF-8 whether the LANG is set
  298. to utf-8 or UTF-8.
  299. On Mac OS X, it returns the same case as the LANG input.
  300. So let tranform result of nl_langinfo (CODESET) to upper case unconditionally. */
  301. term_encoding = g_ascii_strup (nl_langinfo (CODESET), -1);
  302. }
  303. return term_encoding;
  304. }
  305. /* --------------------------------------------------------------------------------------------- */
  306. gboolean
  307. str_isutf8 (const char *codeset_name)
  308. {
  309. return (str_test_encoding_class (codeset_name, str_utf8_encodings) != 0);
  310. }
  311. /* --------------------------------------------------------------------------------------------- */
  312. void
  313. str_init_strings (const char *termenc)
  314. {
  315. codeset = termenc != NULL ? g_ascii_strup (termenc, -1) : g_strdup (str_detect_termencoding ());
  316. str_cnv_not_convert = g_iconv_open (codeset, codeset);
  317. if (str_cnv_not_convert == INVALID_CONV)
  318. {
  319. if (termenc != NULL)
  320. {
  321. g_free (codeset);
  322. codeset = g_strdup (str_detect_termencoding ());
  323. str_cnv_not_convert = g_iconv_open (codeset, codeset);
  324. }
  325. if (str_cnv_not_convert == INVALID_CONV)
  326. {
  327. g_free (codeset);
  328. codeset = g_strdup (DEFAULT_CHARSET);
  329. str_cnv_not_convert = g_iconv_open (codeset, codeset);
  330. }
  331. }
  332. str_cnv_to_term = str_cnv_not_convert;
  333. str_cnv_from_term = str_cnv_not_convert;
  334. str_choose_str_functions ();
  335. }
  336. /* --------------------------------------------------------------------------------------------- */
  337. void
  338. str_uninit_strings (void)
  339. {
  340. if (str_cnv_not_convert != INVALID_CONV)
  341. g_iconv_close (str_cnv_not_convert);
  342. g_free (term_encoding);
  343. g_free (codeset);
  344. }
  345. /* --------------------------------------------------------------------------------------------- */
  346. const char *
  347. str_term_form (const char *text)
  348. {
  349. return used_class.term_form (text);
  350. }
  351. /* --------------------------------------------------------------------------------------------- */
  352. const char *
  353. str_fit_to_term (const char *text, int width, align_crt_t just_mode)
  354. {
  355. return used_class.fit_to_term (text, width, just_mode);
  356. }
  357. /* --------------------------------------------------------------------------------------------- */
  358. const char *
  359. str_term_trim (const char *text, int width)
  360. {
  361. return used_class.term_trim (text, width);
  362. }
  363. /* --------------------------------------------------------------------------------------------- */
  364. const char *
  365. str_term_substring (const char *text, int start, int width)
  366. {
  367. return used_class.term_substring (text, start, width);
  368. }
  369. /* --------------------------------------------------------------------------------------------- */
  370. char *
  371. str_get_next_char (char *text)
  372. {
  373. used_class.cnext_char ((const char **) &text);
  374. return text;
  375. }
  376. /* --------------------------------------------------------------------------------------------- */
  377. const char *
  378. str_cget_next_char (const char *text)
  379. {
  380. used_class.cnext_char (&text);
  381. return text;
  382. }
  383. /* --------------------------------------------------------------------------------------------- */
  384. void
  385. str_next_char (char **text)
  386. {
  387. used_class.cnext_char ((const char **) text);
  388. }
  389. /* --------------------------------------------------------------------------------------------- */
  390. void
  391. str_cnext_char (const char **text)
  392. {
  393. used_class.cnext_char (text);
  394. }
  395. /* --------------------------------------------------------------------------------------------- */
  396. char *
  397. str_get_prev_char (char *text)
  398. {
  399. used_class.cprev_char ((const char **) &text);
  400. return text;
  401. }
  402. /* --------------------------------------------------------------------------------------------- */
  403. const char *
  404. str_cget_prev_char (const char *text)
  405. {
  406. used_class.cprev_char (&text);
  407. return text;
  408. }
  409. /* --------------------------------------------------------------------------------------------- */
  410. void
  411. str_prev_char (char **text)
  412. {
  413. used_class.cprev_char ((const char **) text);
  414. }
  415. /* --------------------------------------------------------------------------------------------- */
  416. void
  417. str_cprev_char (const char **text)
  418. {
  419. used_class.cprev_char (text);
  420. }
  421. /* --------------------------------------------------------------------------------------------- */
  422. char *
  423. str_get_next_char_safe (char *text)
  424. {
  425. used_class.cnext_char_safe ((const char **) &text);
  426. return text;
  427. }
  428. /* --------------------------------------------------------------------------------------------- */
  429. const char *
  430. str_cget_next_char_safe (const char *text)
  431. {
  432. used_class.cnext_char_safe (&text);
  433. return text;
  434. }
  435. /* --------------------------------------------------------------------------------------------- */
  436. void
  437. str_next_char_safe (char **text)
  438. {
  439. used_class.cnext_char_safe ((const char **) text);
  440. }
  441. /* --------------------------------------------------------------------------------------------- */
  442. void
  443. str_cnext_char_safe (const char **text)
  444. {
  445. used_class.cnext_char_safe (text);
  446. }
  447. /* --------------------------------------------------------------------------------------------- */
  448. char *
  449. str_get_prev_char_safe (char *text)
  450. {
  451. used_class.cprev_char_safe ((const char **) &text);
  452. return text;
  453. }
  454. /* --------------------------------------------------------------------------------------------- */
  455. const char *
  456. str_cget_prev_char_safe (const char *text)
  457. {
  458. used_class.cprev_char_safe (&text);
  459. return text;
  460. }
  461. /* --------------------------------------------------------------------------------------------- */
  462. void
  463. str_prev_char_safe (char **text)
  464. {
  465. used_class.cprev_char_safe ((const char **) text);
  466. }
  467. /* --------------------------------------------------------------------------------------------- */
  468. void
  469. str_cprev_char_safe (const char **text)
  470. {
  471. used_class.cprev_char_safe (text);
  472. }
  473. /* --------------------------------------------------------------------------------------------- */
  474. int
  475. str_next_noncomb_char (char **text)
  476. {
  477. return used_class.cnext_noncomb_char ((const char **) text);
  478. }
  479. /* --------------------------------------------------------------------------------------------- */
  480. int
  481. str_cnext_noncomb_char (const char **text)
  482. {
  483. return used_class.cnext_noncomb_char (text);
  484. }
  485. /* --------------------------------------------------------------------------------------------- */
  486. int
  487. str_prev_noncomb_char (char **text, const char *begin)
  488. {
  489. return used_class.cprev_noncomb_char ((const char **) text, begin);
  490. }
  491. /* --------------------------------------------------------------------------------------------- */
  492. int
  493. str_cprev_noncomb_char (const char **text, const char *begin)
  494. {
  495. return used_class.cprev_noncomb_char (text, begin);
  496. }
  497. /* --------------------------------------------------------------------------------------------- */
  498. int
  499. str_is_valid_char (const char *ch, size_t size)
  500. {
  501. return used_class.is_valid_char (ch, size);
  502. }
  503. /* --------------------------------------------------------------------------------------------- */
  504. int
  505. str_term_width1 (const char *text)
  506. {
  507. return used_class.term_width1 (text);
  508. }
  509. /* --------------------------------------------------------------------------------------------- */
  510. int
  511. str_term_width2 (const char *text, size_t length)
  512. {
  513. return used_class.term_width2 (text, length);
  514. }
  515. /* --------------------------------------------------------------------------------------------- */
  516. int
  517. str_term_char_width (const char *text)
  518. {
  519. return used_class.term_char_width (text);
  520. }
  521. /* --------------------------------------------------------------------------------------------- */
  522. int
  523. str_offset_to_pos (const char *text, size_t length)
  524. {
  525. return used_class.offset_to_pos (text, length);
  526. }
  527. /* --------------------------------------------------------------------------------------------- */
  528. int
  529. str_length (const char *text)
  530. {
  531. return used_class.length (text);
  532. }
  533. /* --------------------------------------------------------------------------------------------- */
  534. int
  535. str_length_char (const char *text)
  536. {
  537. return str_cget_next_char_safe (text) - text;
  538. }
  539. /* --------------------------------------------------------------------------------------------- */
  540. int
  541. str_length2 (const char *text, int size)
  542. {
  543. return used_class.length2 (text, size);
  544. }
  545. /* --------------------------------------------------------------------------------------------- */
  546. int
  547. str_length_noncomb (const char *text)
  548. {
  549. return used_class.length_noncomb (text);
  550. }
  551. /* --------------------------------------------------------------------------------------------- */
  552. int
  553. str_column_to_pos (const char *text, size_t pos)
  554. {
  555. return used_class.column_to_pos (text, pos);
  556. }
  557. /* --------------------------------------------------------------------------------------------- */
  558. int
  559. str_isspace (const char *ch)
  560. {
  561. return used_class.char_isspace (ch);
  562. }
  563. /* --------------------------------------------------------------------------------------------- */
  564. int
  565. str_ispunct (const char *ch)
  566. {
  567. return used_class.char_ispunct (ch);
  568. }
  569. /* --------------------------------------------------------------------------------------------- */
  570. int
  571. str_isalnum (const char *ch)
  572. {
  573. return used_class.char_isalnum (ch);
  574. }
  575. /* --------------------------------------------------------------------------------------------- */
  576. int
  577. str_isdigit (const char *ch)
  578. {
  579. return used_class.char_isdigit (ch);
  580. }
  581. /* --------------------------------------------------------------------------------------------- */
  582. int
  583. str_toupper (const char *ch, char **out, size_t * remain)
  584. {
  585. return used_class.char_toupper (ch, out, remain);
  586. }
  587. /* --------------------------------------------------------------------------------------------- */
  588. int
  589. str_tolower (const char *ch, char **out, size_t * remain)
  590. {
  591. return used_class.char_tolower (ch, out, remain);
  592. }
  593. /* --------------------------------------------------------------------------------------------- */
  594. int
  595. str_isprint (const char *ch)
  596. {
  597. return used_class.char_isprint (ch);
  598. }
  599. /* --------------------------------------------------------------------------------------------- */
  600. gboolean
  601. str_iscombiningmark (const char *ch)
  602. {
  603. return used_class.char_iscombiningmark (ch);
  604. }
  605. /* --------------------------------------------------------------------------------------------- */
  606. const char *
  607. str_trunc (const char *text, int width)
  608. {
  609. return used_class.trunc (text, width);
  610. }
  611. /* --------------------------------------------------------------------------------------------- */
  612. char *
  613. str_create_search_needle (const char *needle, int case_sen)
  614. {
  615. return used_class.create_search_needle (needle, case_sen);
  616. }
  617. /* --------------------------------------------------------------------------------------------- */
  618. void
  619. str_release_search_needle (char *needle, int case_sen)
  620. {
  621. used_class.release_search_needle (needle, case_sen);
  622. }
  623. /* --------------------------------------------------------------------------------------------- */
  624. const char *
  625. str_search_first (const char *text, const char *search, int case_sen)
  626. {
  627. return used_class.search_first (text, search, case_sen);
  628. }
  629. /* --------------------------------------------------------------------------------------------- */
  630. const char *
  631. str_search_last (const char *text, const char *search, int case_sen)
  632. {
  633. return used_class.search_last (text, search, case_sen);
  634. }
  635. /* --------------------------------------------------------------------------------------------- */
  636. int
  637. str_is_valid_string (const char *text)
  638. {
  639. return used_class.is_valid_string (text);
  640. }
  641. /* --------------------------------------------------------------------------------------------- */
  642. int
  643. str_compare (const char *t1, const char *t2)
  644. {
  645. return used_class.compare (t1, t2);
  646. }
  647. /* --------------------------------------------------------------------------------------------- */
  648. int
  649. str_ncompare (const char *t1, const char *t2)
  650. {
  651. return used_class.ncompare (t1, t2);
  652. }
  653. /* --------------------------------------------------------------------------------------------- */
  654. int
  655. str_casecmp (const char *t1, const char *t2)
  656. {
  657. return used_class.casecmp (t1, t2);
  658. }
  659. /* --------------------------------------------------------------------------------------------- */
  660. int
  661. str_ncasecmp (const char *t1, const char *t2)
  662. {
  663. return used_class.ncasecmp (t1, t2);
  664. }
  665. /* --------------------------------------------------------------------------------------------- */
  666. int
  667. str_prefix (const char *text, const char *prefix)
  668. {
  669. return used_class.prefix (text, prefix);
  670. }
  671. /* --------------------------------------------------------------------------------------------- */
  672. int
  673. str_caseprefix (const char *text, const char *prefix)
  674. {
  675. return used_class.caseprefix (text, prefix);
  676. }
  677. /* --------------------------------------------------------------------------------------------- */
  678. void
  679. str_fix_string (char *text)
  680. {
  681. used_class.fix_string (text);
  682. }
  683. /* --------------------------------------------------------------------------------------------- */
  684. char *
  685. str_create_key (const char *text, int case_sen)
  686. {
  687. return used_class.create_key (text, case_sen);
  688. }
  689. /* --------------------------------------------------------------------------------------------- */
  690. char *
  691. str_create_key_for_filename (const char *text, int case_sen)
  692. {
  693. return used_class.create_key_for_filename (text, case_sen);
  694. }
  695. /* --------------------------------------------------------------------------------------------- */
  696. int
  697. str_key_collate (const char *t1, const char *t2, int case_sen)
  698. {
  699. return used_class.key_collate (t1, t2, case_sen);
  700. }
  701. /* --------------------------------------------------------------------------------------------- */
  702. void
  703. str_release_key (char *key, int case_sen)
  704. {
  705. used_class.release_key (key, case_sen);
  706. }
  707. /* --------------------------------------------------------------------------------------------- */
  708. void
  709. str_msg_term_size (const char *text, int *lines, int *columns)
  710. {
  711. char *p, *tmp;
  712. char *q;
  713. char c = '\0';
  714. *lines = 1;
  715. *columns = 0;
  716. tmp = g_strdup (text);
  717. p = tmp;
  718. while (TRUE)
  719. {
  720. int width;
  721. q = strchr (p, '\n');
  722. if (q != NULL)
  723. {
  724. c = q[0];
  725. q[0] = '\0';
  726. }
  727. width = str_term_width1 (p);
  728. if (width > *columns)
  729. *columns = width;
  730. if (q == NULL)
  731. break;
  732. q[0] = c;
  733. p = q + 1;
  734. (*lines)++;
  735. }
  736. g_free (tmp);
  737. }
  738. /* --------------------------------------------------------------------------------------------- */
  739. char *
  740. strrstr_skip_count (const char *haystack, const char *needle, size_t skip_count)
  741. {
  742. char *semi;
  743. ssize_t len;
  744. len = strlen (haystack);
  745. do
  746. {
  747. semi = g_strrstr_len (haystack, len, needle);
  748. if (semi == NULL)
  749. return NULL;
  750. len = semi - haystack - 1;
  751. }
  752. while (skip_count-- != 0);
  753. return semi;
  754. }
  755. /* --------------------------------------------------------------------------------------------- */
  756. /* Interprete string as a non-negative decimal integer, optionally multiplied by various values.
  757. *
  758. * @param str input value
  759. * @param invalid set to TRUE if "str" does not represent a number in this format
  760. *
  761. * @return non-integer representation of "str", 0 in case of error.
  762. */
  763. uintmax_t
  764. parse_integer (const char *str, gboolean * invalid)
  765. {
  766. uintmax_t n;
  767. char *suffix;
  768. strtol_error_t e;
  769. e = xstrtoumax (str, &suffix, 10, &n, "bcEGkKMPTwYZ0");
  770. if (e == LONGINT_INVALID_SUFFIX_CHAR && *suffix == 'x')
  771. {
  772. uintmax_t multiplier;
  773. multiplier = parse_integer (suffix + 1, invalid);
  774. if (multiplier != 0 && n * multiplier / multiplier != n)
  775. {
  776. *invalid = TRUE;
  777. return 0;
  778. }
  779. n *= multiplier;
  780. }
  781. else if (e != LONGINT_OK)
  782. {
  783. *invalid = TRUE;
  784. n = 0;
  785. }
  786. return n;
  787. }
  788. /* --------------------------------------------------------------------------------------------- */