Added -g, --oldmouse option to support of NORMAL/BUTTON_EVENT mouse type.
[midnight-commander.git] / lib / strutil / strutil.c
blob4117b0b6973fa028d28aa237e15405fc6399a242
1 /* common strings utilities
2 Copyright (C) 2007 Free Software Foundation, Inc.
4 Written 2007 by:
5 Rostislav Benes
7 The file_date routine is mostly from GNU's fileutils package,
8 written by Richard Stallman and David MacKenzie.
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include <config.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <langinfo.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <stdarg.h>
33 #include "lib/global.h"
34 #include "lib/strutil.h"
36 /*names, that are used for utf-8 */
37 static const char *str_utf8_encodings[] = {
38 "utf-8",
39 "utf8",
40 NULL
43 /* standard 8bit encodings, no wide or multibytes characters */
44 static const char *str_8bit_encodings[] = {
45 "cp-1251",
46 "cp1251",
47 "cp-1250",
48 "cp1250",
49 "cp-866",
50 "cp866",
51 "ibm-866",
52 "ibm866",
53 "cp-850",
54 "cp850",
55 "cp-852",
56 "cp852",
57 "iso-8859",
58 "iso8859",
59 "koi8",
60 NULL
63 /* terminal encoding */
64 static char *codeset = NULL;
65 /* function for encoding specific operations */
66 static struct str_class used_class;
68 GIConv str_cnv_to_term;
69 GIConv str_cnv_from_term;
70 GIConv str_cnv_not_convert;
72 /* if enc is same encoding like on terminal */
73 static int
74 str_test_not_convert (const char *enc)
76 return g_ascii_strcasecmp (enc, codeset) == 0;
79 GIConv
80 str_crt_conv_to (const char *to_enc)
82 return (!str_test_not_convert (to_enc)) ? g_iconv_open (to_enc, codeset) : str_cnv_not_convert;
85 GIConv
86 str_crt_conv_from (const char *from_enc)
88 return (!str_test_not_convert (from_enc))
89 ? g_iconv_open (codeset, from_enc) : str_cnv_not_convert;
92 void
93 str_close_conv (GIConv conv)
95 if (conv != str_cnv_not_convert)
96 g_iconv_close (conv);
99 static estr_t
100 _str_convert (GIConv coder, const char *string, int size, GString * buffer)
102 estr_t state = ESTR_SUCCESS;
103 gchar *tmp_buff = NULL;
104 gssize left;
105 gsize bytes_read = 0;
106 gsize bytes_written = 0;
107 GError *error = NULL;
108 errno = 0;
110 if (coder == INVALID_CONV)
111 return ESTR_FAILURE;
113 if (string == NULL || buffer == NULL)
114 return ESTR_FAILURE;
117 if (! used_class.is_valid_string (string))
119 return ESTR_FAILURE;
122 if (size < 0)
124 size = strlen (string);
126 else
128 left = strlen (string);
129 if (left < size)
130 size = left;
133 left = size;
134 g_iconv (coder, NULL, NULL, NULL, NULL);
136 while (left)
138 tmp_buff = g_convert_with_iconv ((const gchar *) string,
139 left, coder, &bytes_read, &bytes_written, &error);
140 if (error)
142 int code = error->code;
144 g_error_free (error);
145 error = NULL;
147 switch (code)
149 case G_CONVERT_ERROR_NO_CONVERSION:
150 /* Conversion between the requested character sets is not supported. */
151 tmp_buff = g_strnfill (strlen (string), '?');
152 g_string_append (buffer, tmp_buff);
153 g_free (tmp_buff);
154 return ESTR_FAILURE;
156 case G_CONVERT_ERROR_ILLEGAL_SEQUENCE:
157 /* Invalid byte sequence in conversion input. */
158 if ((tmp_buff == NULL) && (bytes_read != 0))
159 /* recode valid byte sequence */
160 tmp_buff = g_convert_with_iconv ((const gchar *) string,
161 bytes_read, coder, NULL, NULL, NULL);
163 if (tmp_buff != NULL)
165 g_string_append (buffer, tmp_buff);
166 g_free (tmp_buff);
169 if ((int) bytes_read < left)
171 string += bytes_read + 1;
172 size -= (bytes_read + 1);
173 left -= (bytes_read + 1);
174 g_string_append_c (buffer, *(string - 1));
176 else
178 return ESTR_PROBLEM;
180 state = ESTR_PROBLEM;
181 break;
183 case G_CONVERT_ERROR_PARTIAL_INPUT:
184 /* Partial character sequence at end of input. */
185 g_string_append (buffer, tmp_buff);
186 g_free (tmp_buff);
187 if ((int) bytes_read < left)
189 left = left - bytes_read;
190 tmp_buff = g_strnfill (left, '?');
191 g_string_append (buffer, tmp_buff);
192 g_free (tmp_buff);
194 return ESTR_PROBLEM;
196 case G_CONVERT_ERROR_BAD_URI: /* Don't know how handle this error :( */
197 case G_CONVERT_ERROR_NOT_ABSOLUTE_PATH: /* Don't know how handle this error :( */
198 case G_CONVERT_ERROR_FAILED: /* Conversion failed for some reason. */
199 default:
200 g_free (tmp_buff);
201 return ESTR_FAILURE;
204 else
206 if (tmp_buff != NULL)
208 if (*tmp_buff)
210 g_string_append (buffer, tmp_buff);
211 g_free (tmp_buff);
212 string += bytes_read;
213 left -= bytes_read;
215 else
217 g_free (tmp_buff);
218 g_string_append (buffer, string);
219 return state;
222 else
224 g_string_append (buffer, string);
225 return ESTR_PROBLEM;
229 return state;
232 estr_t
233 str_convert (GIConv coder, const char *string, GString * buffer)
235 return _str_convert (coder, string, -1, buffer);
238 estr_t
239 str_nconvert (GIConv coder, const char *string, int size, GString * buffer)
241 return _str_convert (coder, string, size, buffer);
244 gchar *
245 str_conv_gerror_message (GError * error, const char *def_msg)
247 return used_class.conv_gerror_message (error, def_msg);
250 estr_t
251 str_vfs_convert_from (GIConv coder, const char *string, GString * buffer)
253 estr_t result;
255 if (coder == str_cnv_not_convert)
257 g_string_append (buffer, string != NULL ? string : "");
258 result = ESTR_SUCCESS;
260 else
261 result = _str_convert (coder, string, -1, buffer);
263 return result;
266 estr_t
267 str_vfs_convert_to (GIConv coder, const char *string, int size, GString * buffer)
269 return used_class.vfs_convert_to (coder, string, size, buffer);
272 void
273 str_printf (GString * buffer, const char *format, ...)
275 va_list ap;
276 va_start (ap, format);
277 #if GLIB_CHECK_VERSION (2, 14, 0)
278 g_string_append_vprintf (buffer, format, ap);
279 #else
281 gchar *tmp;
282 tmp = g_strdup_vprintf (format, ap);
283 g_string_append (buffer, tmp);
284 g_free (tmp);
286 #endif
287 va_end (ap);
290 void
291 str_insert_replace_char (GString * buffer)
293 used_class.insert_replace_char (buffer);
296 estr_t
297 str_translate_char (GIConv conv, const char *keys, size_t ch_size, char *output, size_t out_size)
299 size_t left;
300 size_t cnv;
302 g_iconv (conv, NULL, NULL, NULL, NULL);
304 left = (ch_size == (size_t) (-1)) ? strlen (keys) : ch_size;
306 cnv = g_iconv (conv, (gchar **) & keys, &left, &output, &out_size);
307 if (cnv == (size_t) (-1))
309 return (errno == EINVAL) ? ESTR_PROBLEM : ESTR_FAILURE;
311 else
313 output[0] = '\0';
314 return ESTR_SUCCESS;
319 const char *
320 str_detect_termencoding (void)
322 return (nl_langinfo (CODESET));
325 static int
326 str_test_encoding_class (const char *encoding, const char **table)
328 int t;
329 int result = 0;
330 if (encoding == NULL)
331 return result;
333 for (t = 0; table[t] != NULL; t++)
335 result += (g_ascii_strncasecmp (encoding, table[t], strlen (table[t])) == 0);
337 return result;
340 static void
341 str_choose_str_functions (void)
343 if (str_test_encoding_class (codeset, str_utf8_encodings))
345 used_class = str_utf8_init ();
347 else if (str_test_encoding_class (codeset, str_8bit_encodings))
349 used_class = str_8bit_init ();
351 else
353 used_class = str_ascii_init ();
357 gboolean
358 str_isutf8 (const char *codeset_name)
360 return (str_test_encoding_class (codeset_name, str_utf8_encodings) != 0);
363 void
364 str_init_strings (const char *termenc)
366 codeset = g_strdup ((termenc != NULL) ? termenc : str_detect_termencoding ());
368 str_cnv_not_convert = g_iconv_open (codeset, codeset);
369 if (str_cnv_not_convert == INVALID_CONV)
371 if (termenc != NULL)
373 g_free (codeset);
374 codeset = g_strdup (str_detect_termencoding ());
375 str_cnv_not_convert = g_iconv_open (codeset, codeset);
378 if (str_cnv_not_convert == INVALID_CONV)
380 g_free (codeset);
381 codeset = g_strdup ("ascii");
382 str_cnv_not_convert = g_iconv_open (codeset, codeset);
386 str_cnv_to_term = str_cnv_not_convert;
387 str_cnv_from_term = str_cnv_not_convert;
389 str_choose_str_functions ();
392 void
393 str_uninit_strings (void)
395 if (str_cnv_not_convert != INVALID_CONV)
396 g_iconv_close (str_cnv_not_convert);
397 g_free (codeset);
400 const char *
401 str_term_form (const char *text)
403 return used_class.term_form (text);
406 const char *
407 str_fit_to_term (const char *text, int width, align_crt_t just_mode)
409 return used_class.fit_to_term (text, width, just_mode);
412 const char *
413 str_term_trim (const char *text, int width)
415 return used_class.term_trim (text, width);
418 const char *
419 str_term_substring (const char *text, int start, int width)
421 return used_class.term_substring (text, start, width);
424 char *
425 str_get_next_char (char *text)
428 used_class.cnext_char ((const char **) &text);
429 return text;
432 const char *
433 str_cget_next_char (const char *text)
435 used_class.cnext_char (&text);
436 return text;
439 void
440 str_next_char (char **text)
442 used_class.cnext_char ((const char **) text);
445 void
446 str_cnext_char (const char **text)
448 used_class.cnext_char (text);
451 char *
452 str_get_prev_char (char *text)
454 used_class.cprev_char ((const char **) &text);
455 return text;
458 const char *
459 str_cget_prev_char (const char *text)
461 used_class.cprev_char (&text);
462 return text;
465 void
466 str_prev_char (char **text)
468 used_class.cprev_char ((const char **) text);
471 void
472 str_cprev_char (const char **text)
474 used_class.cprev_char (text);
477 char *
478 str_get_next_char_safe (char *text)
480 used_class.cnext_char_safe ((const char **) &text);
481 return text;
484 const char *
485 str_cget_next_char_safe (const char *text)
487 used_class.cnext_char_safe (&text);
488 return text;
491 void
492 str_next_char_safe (char **text)
494 used_class.cnext_char_safe ((const char **) text);
497 void
498 str_cnext_char_safe (const char **text)
500 used_class.cnext_char_safe (text);
503 char *
504 str_get_prev_char_safe (char *text)
506 used_class.cprev_char_safe ((const char **) &text);
507 return text;
510 const char *
511 str_cget_prev_char_safe (const char *text)
513 used_class.cprev_char_safe (&text);
514 return text;
517 void
518 str_prev_char_safe (char **text)
520 used_class.cprev_char_safe ((const char **) text);
523 void
524 str_cprev_char_safe (const char **text)
526 used_class.cprev_char_safe (text);
530 str_next_noncomb_char (char **text)
532 return used_class.cnext_noncomb_char ((const char **) text);
536 str_cnext_noncomb_char (const char **text)
538 return used_class.cnext_noncomb_char (text);
542 str_prev_noncomb_char (char **text, const char *begin)
544 return used_class.cprev_noncomb_char ((const char **) text, begin);
548 str_cprev_noncomb_char (const char **text, const char *begin)
550 return used_class.cprev_noncomb_char (text, begin);
554 str_is_valid_char (const char *ch, size_t size)
556 return used_class.is_valid_char (ch, size);
560 str_term_width1 (const char *text)
562 return used_class.term_width1 (text);
566 str_term_width2 (const char *text, size_t length)
568 return used_class.term_width2 (text, length);
572 str_term_char_width (const char *text)
574 return used_class.term_char_width (text);
578 str_offset_to_pos (const char *text, size_t length)
580 return used_class.offset_to_pos (text, length);
584 str_length (const char *text)
586 return used_class.length (text);
590 str_length_char (const char *text)
592 return str_cget_next_char_safe (text) - text;
596 str_length2 (const char *text, int size)
598 return used_class.length2 (text, size);
602 str_length_noncomb (const char *text)
604 return used_class.length_noncomb (text);
608 str_column_to_pos (const char *text, size_t pos)
610 return used_class.column_to_pos (text, pos);
614 str_isspace (const char *ch)
616 return used_class.isspace (ch);
620 str_ispunct (const char *ch)
622 return used_class.ispunct (ch);
626 str_isalnum (const char *ch)
628 return used_class.isalnum (ch);
632 str_isdigit (const char *ch)
634 return used_class.isdigit (ch);
638 str_toupper (const char *ch, char **out, size_t * remain)
640 return used_class.toupper (ch, out, remain);
644 str_tolower (const char *ch, char **out, size_t * remain)
646 return used_class.tolower (ch, out, remain);
650 str_isprint (const char *ch)
652 return used_class.isprint (ch);
656 str_iscombiningmark (const char *ch)
658 return used_class.iscombiningmark (ch);
661 const char *
662 str_trunc (const char *text, int width)
664 return used_class.trunc (text, width);
667 char *
668 str_create_search_needle (const char *needle, int case_sen)
670 return used_class.create_search_needle (needle, case_sen);
674 void
675 str_release_search_needle (char *needle, int case_sen)
677 used_class.release_search_needle (needle, case_sen);
680 const char *
681 str_search_first (const char *text, const char *search, int case_sen)
683 return used_class.search_first (text, search, case_sen);
686 const char *
687 str_search_last (const char *text, const char *search, int case_sen)
689 return used_class.search_last (text, search, case_sen);
693 str_is_valid_string (const char *text)
695 return used_class.is_valid_string (text);
699 str_compare (const char *t1, const char *t2)
701 return used_class.compare (t1, t2);
705 str_ncompare (const char *t1, const char *t2)
707 return used_class.ncompare (t1, t2);
711 str_casecmp (const char *t1, const char *t2)
713 return used_class.casecmp (t1, t2);
717 str_ncasecmp (const char *t1, const char *t2)
719 return used_class.ncasecmp (t1, t2);
723 str_prefix (const char *text, const char *prefix)
725 return used_class.prefix (text, prefix);
729 str_caseprefix (const char *text, const char *prefix)
731 return used_class.caseprefix (text, prefix);
734 void
735 str_fix_string (char *text)
737 used_class.fix_string (text);
740 char *
741 str_create_key (const char *text, int case_sen)
743 return used_class.create_key (text, case_sen);
746 char *
747 str_create_key_for_filename (const char *text, int case_sen)
749 return used_class.create_key_for_filename (text, case_sen);
753 str_key_collate (const char *t1, const char *t2, int case_sen)
755 return used_class.key_collate (t1, t2, case_sen);
758 void
759 str_release_key (char *key, int case_sen)
761 used_class.release_key (key, case_sen);
764 void
765 str_msg_term_size (const char *text, int *lines, int *columns)
767 char *p, *tmp;
768 char *q;
769 char c = '\0';
770 int width;
772 *lines = 1;
773 *columns = 0;
775 tmp = g_strdup (text);
776 p = tmp;
778 while (TRUE)
780 q = strchr (p, '\n');
781 if (q != NULL)
783 c = q[0];
784 q[0] = '\0';
787 width = str_term_width1 (p);
788 if (width > *columns)
789 *columns = width;
791 if (q == NULL)
792 break;
794 q[0] = c;
795 p = q + 1;
796 (*lines)++;
799 g_free (tmp);
802 /* --------------------------------------------------------------------------------------------- */
804 char *
805 strrstr_skip_count (const char *haystack, const char *needle, size_t skip_count)
807 char *semi;
808 ssize_t len;
810 len = strlen (haystack);
814 semi = g_strrstr_len (haystack, len, needle);
815 if (semi == NULL)
816 return NULL;
817 len = semi - haystack - 1;
819 while (skip_count-- != 0);
820 return semi;
823 /* --------------------------------------------------------------------------------------------- */