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