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, const ssize_t ch_size, char *output,
355 const size_t out_size)
356 {
357 size_t left;
358 size_t cnv;
359 size_t osize = out_size;
360
361 g_iconv (conv, NULL, NULL, NULL, NULL);
362
363 left = ch_size < 0 ? strlen (keys) : (size_t) ch_size;
364
365 cnv = g_iconv (conv, (gchar **) &keys, &left, &output, &osize);
366 if (cnv == (size_t) (-1))
367 return (errno == EINVAL) ? ESTR_PROBLEM : ESTR_FAILURE;
368
369 output[0] = '\0';
370 return ESTR_SUCCESS;
371 }
372
373
374
375 const char *
376 str_detect_termencoding (void)
377 {
378 if (term_encoding == NULL)
379 {
380
381
382
383
384 term_encoding = g_ascii_strup (nl_langinfo (CODESET), -1);
385 }
386
387 return term_encoding;
388 }
389
390
391
392 gboolean
393 str_isutf8 (const char *codeset_name)
394 {
395 return (str_test_encoding_class (codeset_name, str_utf8_encodings) != 0);
396 }
397
398
399
400 void
401 str_init_strings (const char *termenc)
402 {
403 codeset = termenc != NULL ? g_ascii_strup (termenc, -1) : g_strdup (str_detect_termencoding ());
404
405 str_cnv_not_convert = g_iconv_open (codeset, codeset);
406 if (str_cnv_not_convert == INVALID_CONV)
407 {
408 if (termenc != NULL)
409 {
410 g_free (codeset);
411 codeset = g_strdup (str_detect_termencoding ());
412 str_cnv_not_convert = g_iconv_open (codeset, codeset);
413 }
414
415 if (str_cnv_not_convert == INVALID_CONV)
416 {
417 g_free (codeset);
418 codeset = g_strdup (DEFAULT_CHARSET);
419 str_cnv_not_convert = g_iconv_open (codeset, codeset);
420 }
421 }
422
423 str_cnv_to_term = str_cnv_not_convert;
424 str_cnv_from_term = str_cnv_not_convert;
425
426 str_choose_str_functions ();
427 }
428
429
430
431 void
432 str_uninit_strings (void)
433 {
434 if (str_cnv_not_convert != INVALID_CONV)
435 g_iconv_close (str_cnv_not_convert);
436
437 MC_PTR_FREE (term_encoding);
438 MC_PTR_FREE (codeset);
439 }
440
441
442
443 const char *
444 str_term_form (const char *text)
445 {
446 return used_class.term_form (text);
447 }
448
449
450
451 const char *
452 str_fit_to_term (const char *text, int width, align_crt_t just_mode)
453 {
454 return used_class.fit_to_term (text, width, just_mode);
455 }
456
457
458
459 const char *
460 str_term_trim (const char *text, const ssize_t width)
461 {
462 return used_class.term_trim (text, width);
463 }
464
465
466
467 const char *
468 str_term_substring (const char *text, int start, int width)
469 {
470 return used_class.term_substring (text, start, width);
471 }
472
473
474
475 char *
476 str_get_next_char (char *text)
477 {
478
479 used_class.cnext_char ((const char **) &text);
480 return text;
481 }
482
483
484
485 const char *
486 str_cget_next_char (const char *text)
487 {
488 used_class.cnext_char (&text);
489 return text;
490 }
491
492
493
494 void
495 str_next_char (char **text)
496 {
497 used_class.cnext_char ((const char **) text);
498 }
499
500
501
502 void
503 str_cnext_char (const char **text)
504 {
505 used_class.cnext_char (text);
506 }
507
508
509
510 char *
511 str_get_prev_char (char *text)
512 {
513 used_class.cprev_char ((const char **) &text);
514 return text;
515 }
516
517
518
519 const char *
520 str_cget_prev_char (const char *text)
521 {
522 used_class.cprev_char (&text);
523 return text;
524 }
525
526
527
528 void
529 str_prev_char (char **text)
530 {
531 used_class.cprev_char ((const char **) text);
532 }
533
534
535
536 void
537 str_cprev_char (const char **text)
538 {
539 used_class.cprev_char (text);
540 }
541
542
543
544 char *
545 str_get_next_char_safe (char *text)
546 {
547 used_class.cnext_char_safe ((const char **) &text);
548 return text;
549 }
550
551
552
553 const char *
554 str_cget_next_char_safe (const char *text)
555 {
556 used_class.cnext_char_safe (&text);
557 return text;
558 }
559
560
561
562 void
563 str_next_char_safe (char **text)
564 {
565 used_class.cnext_char_safe ((const char **) text);
566 }
567
568
569
570 void
571 str_cnext_char_safe (const char **text)
572 {
573 used_class.cnext_char_safe (text);
574 }
575
576
577
578 char *
579 str_get_prev_char_safe (char *text)
580 {
581 used_class.cprev_char_safe ((const char **) &text);
582 return text;
583 }
584
585
586
587 const char *
588 str_cget_prev_char_safe (const char *text)
589 {
590 used_class.cprev_char_safe (&text);
591 return text;
592 }
593
594
595
596 void
597 str_prev_char_safe (char **text)
598 {
599 used_class.cprev_char_safe ((const char **) text);
600 }
601
602
603
604 void
605 str_cprev_char_safe (const char **text)
606 {
607 used_class.cprev_char_safe (text);
608 }
609
610
611
612 int
613 str_next_noncomb_char (char **text)
614 {
615 return used_class.cnext_noncomb_char ((const char **) text);
616 }
617
618
619
620 int
621 str_cnext_noncomb_char (const char **text)
622 {
623 return used_class.cnext_noncomb_char (text);
624 }
625
626
627
628 int
629 str_prev_noncomb_char (char **text, const char *begin)
630 {
631 return used_class.cprev_noncomb_char ((const char **) text, begin);
632 }
633
634
635
636 int
637 str_cprev_noncomb_char (const char **text, const char *begin)
638 {
639 return used_class.cprev_noncomb_char (text, begin);
640 }
641
642
643
644 int
645 str_is_valid_char (const char *ch, size_t size)
646 {
647 return used_class.is_valid_char (ch, size);
648 }
649
650
651
652 int
653 str_term_width1 (const char *text)
654 {
655
656
657
658
659 return (int) used_class.term_width1 (text);
660 }
661
662
663
664 int
665 str_term_width2 (const char *text, const ssize_t width)
666 {
667
668
669 return (int) used_class.term_width2 (text, width);
670 }
671
672
673
674 int
675 str_term_char_width (const char *text)
676 {
677 return used_class.term_char_width (text);
678 }
679
680
681
682 int
683 str_offset_to_pos (const char *text, size_t length)
684 {
685 return used_class.offset_to_pos (text, length);
686 }
687
688
689
690 int
691 str_length (const char *text)
692 {
693 return used_class.length (text);
694 }
695
696
697
698 int
699 str_length_char (const char *text)
700 {
701 return str_cget_next_char_safe (text) - text;
702 }
703
704
705
706 int
707 str_length2 (const char *text, int size)
708 {
709 return used_class.length2 (text, size);
710 }
711
712
713
714 int
715 str_length_noncomb (const char *text)
716 {
717 return used_class.length_noncomb (text);
718 }
719
720
721
722 int
723 str_column_to_pos (const char *text, size_t pos)
724 {
725 return used_class.column_to_pos (text, pos);
726 }
727
728
729
730 gboolean
731 str_isspace (const char *ch)
732 {
733 return used_class.char_isspace (ch);
734 }
735
736
737
738 gboolean
739 str_ispunct (const char *ch)
740 {
741 return used_class.char_ispunct (ch);
742 }
743
744
745
746 gboolean
747 str_isalnum (const char *ch)
748 {
749 return used_class.char_isalnum (ch);
750 }
751
752
753
754 gboolean
755 str_isdigit (const char *ch)
756 {
757 return used_class.char_isdigit (ch);
758 }
759
760
761
762 gboolean
763 str_toupper (const char *ch, char **out, size_t *remain)
764 {
765 return used_class.char_toupper (ch, out, remain);
766 }
767
768
769
770 gboolean
771 str_tolower (const char *ch, char **out, size_t *remain)
772 {
773 return used_class.char_tolower (ch, out, remain);
774 }
775
776
777
778 gboolean
779 str_isprint (const char *ch)
780 {
781 return used_class.char_isprint (ch);
782 }
783
784
785
786 gboolean
787 str_iscombiningmark (const char *ch)
788 {
789 return used_class.char_iscombiningmark (ch);
790 }
791
792
793
794 const char *
795 str_trunc (const char *text, const ssize_t width)
796 {
797 return used_class.trunc (text, width);
798 }
799
800
801
802 char *
803 str_create_search_needle (const char *needle, gboolean case_sen)
804 {
805 return used_class.create_search_needle (needle, case_sen);
806 }
807
808
809
810 void
811 str_release_search_needle (char *needle, gboolean case_sen)
812 {
813 used_class.release_search_needle (needle, case_sen);
814 }
815
816
817
818 const char *
819 str_search_first (const char *text, const char *search, gboolean case_sen)
820 {
821 return used_class.search_first (text, search, case_sen);
822 }
823
824
825
826 const char *
827 str_search_last (const char *text, const char *search, gboolean case_sen)
828 {
829 return used_class.search_last (text, search, case_sen);
830 }
831
832
833
834 gboolean
835 str_is_valid_string (const char *text)
836 {
837 return used_class.is_valid_string (text);
838 }
839
840
841
842 int
843 str_compare (const char *t1, const char *t2)
844 {
845 return used_class.compare (t1, t2);
846 }
847
848
849
850 int
851 str_ncompare (const char *t1, const char *t2)
852 {
853 return used_class.ncompare (t1, t2);
854 }
855
856
857
858 int
859 str_casecmp (const char *t1, const char *t2)
860 {
861 return used_class.casecmp (t1, t2);
862 }
863
864
865
866 int
867 str_ncasecmp (const char *t1, const char *t2)
868 {
869 return used_class.ncasecmp (t1, t2);
870 }
871
872
873
874 int
875 str_prefix (const char *text, const char *prefix)
876 {
877 return used_class.prefix (text, prefix);
878 }
879
880
881
882 int
883 str_caseprefix (const char *text, const char *prefix)
884 {
885 return used_class.caseprefix (text, prefix);
886 }
887
888
889
890 void
891 str_fix_string (char *text)
892 {
893 used_class.fix_string (text);
894 }
895
896
897
898 char *
899 str_create_key (const char *text, gboolean case_sen)
900 {
901 return used_class.create_key (text, case_sen);
902 }
903
904
905
906 char *
907 str_create_key_for_filename (const char *text, gboolean case_sen)
908 {
909 return used_class.create_key_for_filename (text, case_sen);
910 }
911
912
913
914 int
915 str_key_collate (const char *t1, const char *t2, gboolean case_sen)
916 {
917 return used_class.key_collate (t1, t2, case_sen);
918 }
919
920
921
922 void
923 str_release_key (char *key, gboolean case_sen)
924 {
925 used_class.release_key (key, case_sen);
926 }
927
928
929
930 void
931 str_msg_term_size (const char *text, int *lines, int *columns)
932 {
933 char *p, *tmp;
934 char *q;
935 char c = '\0';
936
937 *lines = 1;
938 *columns = 0;
939
940 tmp = g_strdup (text);
941 p = tmp;
942
943 while (TRUE)
944 {
945 int width;
946
947 q = strchr (p, '\n');
948 if (q != NULL)
949 {
950 c = q[0];
951 q[0] = '\0';
952 }
953
954 width = str_term_width1 (p);
955 if (width > *columns)
956 *columns = width;
957
958 if (q == NULL)
959 break;
960
961 q[0] = c;
962 p = q + 1;
963 (*lines)++;
964 }
965
966 g_free (tmp);
967 }
968
969
970
971 char *
972 strrstr_skip_count (const char *haystack, const char *needle, size_t skip_count)
973 {
974 char *semi;
975 ssize_t len;
976
977 len = strlen (haystack);
978
979 do
980 {
981 semi = g_strrstr_len (haystack, len, needle);
982 if (semi == NULL)
983 return NULL;
984 len = semi - haystack - 1;
985 }
986 while (skip_count-- != 0);
987
988 return semi;
989 }
990
991
992
993
994
995
996
997
998
999
1000 uintmax_t
1001 parse_integer (const char *str, gboolean *invalid)
1002 {
1003 uintmax_t n;
1004 char *suffix;
1005 strtol_error_t e;
1006
1007 e = xstrtoumax (str, &suffix, 10, &n, "bcEGkKMPTwYZ0");
1008 if (e == LONGINT_INVALID_SUFFIX_CHAR && *suffix == 'x')
1009 {
1010 uintmax_t multiplier;
1011
1012 multiplier = parse_integer (suffix + 1, invalid);
1013 if (multiplier != 0 && n * multiplier / multiplier != n)
1014 {
1015 *invalid = TRUE;
1016 return 0;
1017 }
1018
1019 n *= multiplier;
1020 }
1021 else if (e != LONGINT_OK)
1022 {
1023 *invalid = TRUE;
1024 n = 0;
1025 }
1026
1027 return n;
1028 }
1029
1030
1031
1032
1033
1034
1035 void
1036 str_rstrip_eol (char *s)
1037 {
1038 if (s == NULL || *s == '\0')
1039 return;
1040
1041 const size_t len = strlen (s);
1042 if (len >= 2 && s[len - 2] == '\r' && s[len - 1] == '\n')
1043 s[len - 2] = '\0';
1044 else if (len >= 1 && (s[len - 1] == '\n' || s[len - 1] == '\r'))
1045 s[len - 1] = '\0';
1046 }
1047
1048