done_screen() is moved from src/layout.c to src/main.c.
[midnight-commander.git] / src / strutil.c
blob3be457339b8ee9a447e692419b92fd7e8d6323c6
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 "global.h"
34 #include "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 "cp-850",
52 "cp850",
53 "cp-852",
54 "cp852",
55 "iso-8859",
56 "iso8859",
57 "koi8",
58 NULL
61 /* terminal encoding*/
62 static char *codeset;
63 /* function for encoding specific operations*/
64 static struct str_class used_class;
66 GIConv str_cnv_to_term;
67 GIConv str_cnv_from_term;
68 GIConv str_cnv_not_convert;
70 /* if enc is same encoding like on terminal*/
71 static int
72 str_test_not_convert (const char *enc)
74 return g_ascii_strcasecmp (enc, codeset) == 0;
77 GIConv
78 str_crt_conv_to (const char *to_enc)
80 return (!str_test_not_convert (to_enc))
81 ? g_iconv_open (to_enc, codeset) : str_cnv_not_convert;
84 GIConv
85 str_crt_conv_from (const char *from_enc)
87 return (!str_test_not_convert (from_enc))
88 ? g_iconv_open (codeset, from_enc) : str_cnv_not_convert;
91 void
92 str_close_conv (GIConv conv)
94 if (conv != str_cnv_not_convert)
95 g_iconv_close (conv);
98 static estr_t
99 _str_convert (GIConv coder, const char *string, int size, GString * buffer)
101 estr_t state = ESTR_SUCCESS;
102 gchar *tmp_buff = NULL;
103 gssize left;
104 gsize bytes_read = 0;
105 gsize bytes_written = 0;
106 GError *error = NULL;
107 errno = 0;
109 if (coder == INVALID_CONV)
110 return ESTR_FAILURE;
112 if (string == NULL || buffer == NULL)
113 return ESTR_FAILURE;
116 if (! used_class.is_valid_string (string))
118 return ESTR_FAILURE;
121 if (size < 0)
123 size = strlen (string);
125 else
127 left = strlen (string);
128 if (left < size)
129 size = left;
132 left = size;
133 g_iconv (coder, NULL, NULL, NULL, NULL);
135 while (left)
137 tmp_buff = g_convert_with_iconv ((const gchar *) string,
138 left,
139 coder,
140 &bytes_read,
141 &bytes_written, &error);
142 if (error)
144 int code = error->code;
146 g_error_free (error);
147 error = NULL;
149 switch (code)
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;
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,
164 coder, NULL, NULL, NULL);
166 if (tmp_buff != NULL)
168 g_string_append (buffer, tmp_buff);
169 g_free (tmp_buff);
172 if ((int)bytes_read < left)
174 string += bytes_read + 1;
175 size -= (bytes_read + 1);
176 left -= (bytes_read + 1);
177 g_string_append_c (buffer, *(string-1));
179 else
181 return ESTR_PROBLEM;
183 state = ESTR_PROBLEM;
184 break;
186 case G_CONVERT_ERROR_PARTIAL_INPUT:
187 /* Partial character sequence at end of input. */
188 g_string_append (buffer, tmp_buff);
189 g_free (tmp_buff);
190 if ((int)bytes_read < left)
192 left = left - bytes_read;
193 tmp_buff = g_strnfill (left, '?');
194 g_string_append (buffer, tmp_buff);
195 g_free (tmp_buff);
197 return ESTR_PROBLEM;
199 case G_CONVERT_ERROR_BAD_URI: /* Don't know how handle this error :( */
200 case G_CONVERT_ERROR_NOT_ABSOLUTE_PATH: /* Don't know how handle this error :( */
201 case G_CONVERT_ERROR_FAILED: /* Conversion failed for some reason. */
202 default:
203 g_free (tmp_buff);
204 return ESTR_FAILURE;
207 else
209 if (tmp_buff != NULL)
211 if (*tmp_buff)
213 g_string_append (buffer, tmp_buff);
214 g_free (tmp_buff);
215 string += bytes_read;
216 left -= bytes_read;
218 else
220 g_free (tmp_buff);
221 g_string_append (buffer, string);
222 return state;
225 else
227 g_string_append (buffer, string);
228 return ESTR_PROBLEM;
232 return state;
235 estr_t
236 str_convert (GIConv coder, const char *string, GString * buffer)
238 return _str_convert (coder, string, -1, buffer);
241 estr_t
242 str_nconvert (GIConv coder, const char *string, int size, GString * buffer)
244 return _str_convert (coder, string, size, buffer);
247 gchar *
248 str_conv_gerror_message (GError *error, const char *def_msg)
250 return used_class.conv_gerror_message (error, def_msg);
253 estr_t
254 str_vfs_convert_from (GIConv coder, const char *string, GString * buffer)
256 estr_t result;
258 if (coder == str_cnv_not_convert)
260 g_string_append (buffer, string != NULL ? string : "");
261 result = ESTR_SUCCESS;
263 else
264 result = _str_convert (coder, string, -1, buffer);
266 return result;
269 estr_t
270 str_vfs_convert_to (GIConv coder, const char *string, int size,
271 GString * buffer)
273 return used_class.vfs_convert_to (coder, string, size, buffer);
276 void
277 str_printf (GString * buffer, const char *format, ...)
279 va_list ap;
280 va_start (ap, format);
281 #if GLIB_CHECK_VERSION (2, 14, 0)
282 g_string_append_vprintf (buffer, format, ap);
283 #else
285 gchar *tmp;
286 tmp = g_strdup_vprintf (format, ap);
287 g_string_append (buffer, tmp);
288 g_free(tmp);
290 #endif
291 va_end (ap);
294 void
295 str_insert_replace_char (GString * buffer)
297 used_class.insert_replace_char (buffer);
300 estr_t
301 str_translate_char (GIConv conv, const char *keys, size_t ch_size,
302 char *output, size_t out_size)
304 size_t left;
305 size_t cnv;
307 g_iconv (conv, NULL, NULL, NULL, NULL);
309 left = (ch_size == (size_t) (-1)) ? strlen (keys) : ch_size;
311 cnv = g_iconv (conv, (gchar **) &keys, &left, &output, &out_size);
312 if (cnv == (size_t)(-1)) {
313 return (errno == EINVAL) ? ESTR_PROBLEM : ESTR_FAILURE;
314 } else {
315 output[0] = '\0';
316 return ESTR_SUCCESS;
321 const char *
322 str_detect_termencoding (void)
324 return (nl_langinfo (CODESET));
327 static int
328 str_test_encoding_class (const char *encoding, const char **table)
330 int t;
331 int result = 0;
332 if ( encoding == NULL )
333 return result;
335 for (t = 0; table[t] != NULL; t++)
337 result += (g_ascii_strncasecmp (encoding, table[t],
338 strlen (table[t])) == 0);
340 return result;
343 static void
344 str_choose_str_functions ()
346 if (str_test_encoding_class (codeset, str_utf8_encodings))
348 used_class = str_utf8_init ();
350 else if (str_test_encoding_class (codeset, str_8bit_encodings))
352 used_class = str_8bit_init ();
354 else
356 used_class = str_ascii_init ();
361 str_isutf8 (const char *codeset_name)
363 int result = 0;
364 if (str_test_encoding_class (codeset_name, str_utf8_encodings))
366 result = 1;
368 return result;
371 void
372 str_init_strings (const char *termenc)
374 codeset = g_strdup ((termenc != NULL)
375 ? termenc
376 : str_detect_termencoding ());
378 str_cnv_not_convert = g_iconv_open (codeset, codeset);
379 if (str_cnv_not_convert == INVALID_CONV)
381 if (termenc != NULL)
383 g_free (codeset);
384 codeset = g_strdup (str_detect_termencoding ());
385 str_cnv_not_convert = g_iconv_open (codeset, codeset);
388 if (str_cnv_not_convert == INVALID_CONV)
390 g_free (codeset);
391 codeset = g_strdup ("ascii");
392 str_cnv_not_convert = g_iconv_open (codeset, codeset);
396 str_cnv_to_term = str_cnv_not_convert;
397 str_cnv_from_term = str_cnv_not_convert;
399 str_choose_str_functions ();
402 void
403 str_uninit_strings ()
405 g_iconv_close (str_cnv_not_convert);
408 const char *
409 str_term_form (const char *text)
411 return used_class.term_form (text);
414 const char *
415 str_fit_to_term (const char *text, int width, align_crt_t just_mode)
417 return used_class.fit_to_term (text, width, just_mode);
420 const char *
421 str_term_trim (const char *text, int width)
423 return used_class.term_trim (text, width);
426 void
427 str_msg_term_size (const char *text, int *lines, int *columns)
429 used_class.msg_term_size (text, lines, columns);
432 const char *
433 str_term_substring (const char *text, int start, int width)
435 return used_class.term_substring (text, start, width);
438 char *
439 str_get_next_char (char *text)
442 used_class.cnext_char ((const char **) &text);
443 return text;
446 const char *
447 str_cget_next_char (const char *text)
449 used_class.cnext_char(&text);
450 return text;
453 void
454 str_next_char (char **text)
456 used_class.cnext_char ((const char **) text);
459 void
460 str_cnext_char (const char **text)
462 used_class.cnext_char (text);
465 char *
466 str_get_prev_char (char *text)
468 used_class.cprev_char ((const char **) &text);
469 return text;
472 const char *
473 str_cget_prev_char (const char *text)
475 used_class.cprev_char (&text);
476 return text;
479 void
480 str_prev_char (char **text)
482 used_class.cprev_char ((const char **) text);
485 void
486 str_cprev_char (const char **text)
488 used_class.cprev_char (text);
491 char *
492 str_get_next_char_safe (char *text)
494 used_class.cnext_char_safe ((const char **) &text);
495 return text;
498 const char *
499 str_cget_next_char_safe (const char *text)
501 used_class.cnext_char_safe (&text);
502 return text;
505 void
506 str_next_char_safe (char **text)
508 used_class.cnext_char_safe ((const char **) text);
511 void
512 str_cnext_char_safe (const char **text)
514 used_class.cnext_char_safe (text);
517 char *
518 str_get_prev_char_safe (char *text)
520 used_class.cprev_char_safe ((const char **) &text);
521 return text;
524 const char *
525 str_cget_prev_char_safe (const char *text)
527 used_class.cprev_char_safe (&text);
528 return text;
531 void
532 str_prev_char_safe (char **text)
534 used_class.cprev_char_safe ((const char **) text);
537 void
538 str_cprev_char_safe (const char **text)
540 used_class.cprev_char_safe (text);
544 str_next_noncomb_char (char **text)
546 return used_class.cnext_noncomb_char ((const char **) text);
550 str_cnext_noncomb_char (const char **text)
552 return used_class.cnext_noncomb_char (text);
556 str_prev_noncomb_char (char **text, const char *begin)
558 return used_class.cprev_noncomb_char ((const char **) text, begin);
562 str_cprev_noncomb_char (const char **text, const char *begin)
564 return used_class.cprev_noncomb_char (text, begin);
568 str_is_valid_char (const char *ch, size_t size)
570 return used_class.is_valid_char (ch, size);
574 str_term_width1 (const char *text)
576 return used_class.term_width1 (text);
580 str_term_width2 (const char *text, size_t length)
582 return used_class.term_width2 (text, length);
586 str_term_char_width (const char *text)
588 return used_class.term_char_width (text);
592 str_offset_to_pos (const char *text, size_t length)
594 return used_class.offset_to_pos (text, length);
598 str_length (const char *text)
600 return used_class.length (text);
604 str_length_char (const char *text)
606 return str_cget_next_char_safe (text)-text;
610 str_length2 (const char *text, int size)
612 return used_class.length2 (text, size);
616 str_length_noncomb (const char *text)
618 return used_class.length_noncomb (text);
622 str_column_to_pos (const char *text, size_t pos)
624 return used_class.column_to_pos (text, pos);
628 str_isspace (const char *ch)
630 return used_class.isspace (ch);
634 str_ispunct (const char *ch)
636 return used_class.ispunct (ch);
640 str_isalnum (const char *ch)
642 return used_class.isalnum (ch);
646 str_isdigit (const char *ch)
648 return used_class.isdigit (ch);
652 str_toupper (const char *ch, char **out, size_t * remain)
654 return used_class.toupper (ch, out, remain);
658 str_tolower (const char *ch, char **out, size_t * remain)
660 return used_class.tolower (ch, out, remain);
664 str_isprint (const char *ch)
666 return used_class.isprint (ch);
670 str_iscombiningmark (const char *ch)
672 return used_class.iscombiningmark (ch);
675 const char *
676 str_trunc (const char *text, int width)
678 return used_class.trunc (text, width);
681 char *
682 str_create_search_needle (const char *needle, int case_sen)
684 return used_class.create_search_needle (needle, case_sen);
688 void
689 str_release_search_needle (char *needle, int case_sen)
691 used_class.release_search_needle (needle, case_sen);
694 const char *
695 str_search_first (const char *text, const char *search, int case_sen)
697 return used_class.search_first (text, search, case_sen);
700 const char *
701 str_search_last (const char *text, const char *search, int case_sen)
703 return used_class.search_last (text, search, case_sen);
707 str_is_valid_string (const char *text)
709 return used_class.is_valid_string (text);
713 str_compare (const char *t1, const char *t2)
715 return used_class.compare (t1, t2);
719 str_ncompare (const char *t1, const char *t2)
721 return used_class.ncompare (t1, t2);
725 str_casecmp (const char *t1, const char *t2)
727 return used_class.casecmp (t1, t2);
731 str_ncasecmp (const char *t1, const char *t2)
733 return used_class.ncasecmp (t1, t2);
737 str_prefix (const char *text, const char *prefix)
739 return used_class.prefix (text, prefix);
743 str_caseprefix (const char *text, const char *prefix)
745 return used_class.caseprefix (text, prefix);
748 void
749 str_fix_string (char *text)
751 used_class.fix_string (text);
754 char *
755 str_create_key (const char *text, int case_sen)
757 return used_class.create_key (text, case_sen);
760 char *
761 str_create_key_for_filename (const char *text, int case_sen)
763 return used_class.create_key_for_filename (text, case_sen);
767 str_key_collate (const char *t1, const char *t2, int case_sen)
769 return used_class.key_collate (t1, t2, case_sen);
772 void
773 str_release_key (char *key, int case_sen)
775 used_class.release_key (key, case_sen);