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