4 Copyright (C) 2007, 2011
5 The Free Software Foundation, Inc.
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
31 #include "lib/global.h"
32 #include "lib/strutil.h"
34 /* functions for singlebyte encodings, all characters have width 1
35 * using standard system functions
36 * there are only small differences between functions in strutil8bit.c
40 static const char replch
= '?';
43 * Inlines to equalize 'char' signedness for single 'char' encodings.
45 * isspace((unsigned char)c);
50 #define DECLARE_CTYPE_WRAPPER(func_name) \
51 static inline int char_##func_name(char c) \
53 return func_name((int)(unsigned char)c); \
57 DECLARE_CTYPE_WRAPPER (isalnum
)
58 DECLARE_CTYPE_WRAPPER (isalpha
)
59 DECLARE_CTYPE_WRAPPER (isascii
)
60 DECLARE_CTYPE_WRAPPER (isblank
)
61 DECLARE_CTYPE_WRAPPER (iscntrl
)
62 DECLARE_CTYPE_WRAPPER (isdigit
)
63 DECLARE_CTYPE_WRAPPER (isgraph
)
64 DECLARE_CTYPE_WRAPPER (islower
)
65 DECLARE_CTYPE_WRAPPER (isprint
)
66 DECLARE_CTYPE_WRAPPER (ispunct
)
67 DECLARE_CTYPE_WRAPPER (isspace
)
68 DECLARE_CTYPE_WRAPPER (isupper
)
69 DECLARE_CTYPE_WRAPPER (isxdigit
)
70 DECLARE_CTYPE_WRAPPER (toupper
)
71 DECLARE_CTYPE_WRAPPER (tolower
)
75 str_8bit_insert_replace_char (GString
* buffer
)
77 g_string_append_c (buffer
, replch
);
81 str_8bit_is_valid_string (const char *text
)
88 str_8bit_is_valid_char (const char *ch
, size_t size
)
96 str_8bit_cnext_char (const char **text
)
102 str_8bit_cprev_char (const char **text
)
108 str_8bit_cnext_noncomb_char (const char **text
)
110 if (*text
[0] != '\0')
120 str_8bit_cprev_noncomb_char (const char **text
, const char *begin
)
122 if ((*text
) != begin
)
132 str_8bit_isspace (const char *text
)
134 return char_isspace (text
[0]);
138 str_8bit_ispunct (const char *text
)
140 return char_ispunct (text
[0]);
144 str_8bit_isalnum (const char *text
)
146 return char_isalnum (text
[0]);
150 str_8bit_isdigit (const char *text
)
152 return char_isdigit (text
[0]);
156 str_8bit_isprint (const char *text
)
158 return char_isprint (text
[0]);
162 str_8bit_iscombiningmark (const char *text
)
169 str_8bit_toupper (const char *text
, char **out
, size_t * remain
)
173 (*out
)[0] = char_toupper (text
[0]);
180 str_8bit_tolower (const char *text
, char **out
, size_t * remain
)
184 (*out
)[0] = char_tolower (text
[0]);
191 str_8bit_length (const char *text
)
193 return strlen (text
);
197 str_8bit_length2 (const char *text
, int size
)
199 return (size
>= 0) ? min (strlen (text
), (gsize
) size
) : strlen (text
);
203 str_8bit_conv_gerror_message (GError
* error
, const char *def_msg
)
208 /* glib messages are in UTF-8 charset */
209 conv
= str_crt_conv_from ("UTF-8");
211 if (conv
== INVALID_CONV
)
212 ret
= g_strdup (def_msg
!= NULL
? def_msg
: "");
217 buf
= g_string_new ("");
219 if (str_convert (conv
, error
->message
, buf
) != ESTR_FAILURE
)
222 g_string_free (buf
, FALSE
);
226 ret
= g_strdup (def_msg
!= NULL
? def_msg
: "");
227 g_string_free (buf
, TRUE
);
230 str_close_conv (conv
);
237 str_8bit_vfs_convert_to (GIConv coder
, const char *string
, int size
, GString
* buffer
)
241 if (coder
== str_cnv_not_convert
)
243 g_string_append_len (buffer
, string
, size
);
244 result
= ESTR_SUCCESS
;
247 result
= str_nconvert (coder
, (char *) string
, size
, buffer
);
254 str_8bit_term_form (const char *text
)
256 static char result
[BUF_MEDIUM
];
263 remain
= sizeof (result
);
264 length
= strlen (text
);
266 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
268 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
276 str_8bit_fit_to_term (const char *text
, int width
, align_crt_t just_mode
)
278 static char result
[BUF_MEDIUM
];
285 length
= strlen (text
);
287 remain
= sizeof (result
);
289 if ((int) length
<= width
)
292 switch (HIDE_FIT (just_mode
))
296 ident
= (width
- length
) / 2;
299 ident
= width
- length
;
303 if ((int) remain
<= ident
)
305 memset (actual
, ' ', ident
);
309 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
311 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
313 if (width
- length
- ident
> 0)
315 if (remain
<= width
- length
- ident
)
317 memset (actual
, ' ', width
- length
- ident
);
318 actual
+= width
- length
- ident
;
323 if (IS_FIT (just_mode
))
325 for (; pos
+ 1 <= (gsize
) width
/ 2 && remain
> 1; actual
++, pos
++, remain
--)
328 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
337 pos
+= length
- width
+ 1;
339 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
341 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
347 switch (HIDE_FIT (just_mode
))
350 ident
= (length
- width
) / 2;
353 ident
= length
- width
;
358 for (; pos
< (gsize
) (ident
+ width
) && remain
> 1; pos
++, actual
++, remain
--)
361 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
372 str_8bit_term_trim (const char *text
, int width
)
374 static char result
[BUF_MEDIUM
];
380 length
= strlen (text
);
382 remain
= sizeof (result
);
386 if (width
< (int) length
)
390 memset (actual
, '.', width
);
395 memset (actual
, '.', 3);
399 pos
+= length
- width
+ 3;
401 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
402 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
407 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
408 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
417 str_8bit_term_width2 (const char *text
, size_t length
)
419 return (length
!= (size_t) (-1)) ? min (strlen (text
), length
) : strlen (text
);
423 str_8bit_term_width1 (const char *text
)
425 return str_8bit_term_width2 (text
, (size_t) (-1));
429 str_8bit_term_char_width (const char *text
)
436 str_8bit_term_substring (const char *text
, int start
, int width
)
438 static char result
[BUF_MEDIUM
];
445 remain
= sizeof (result
);
446 length
= strlen (text
);
448 if (start
< (int) length
)
451 for (; pos
< length
&& width
> 0 && remain
> 1; pos
++, width
--, actual
++, remain
--)
454 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
458 for (; width
> 0 && remain
> 1; actual
++, remain
--, width
--)
468 str_8bit_trunc (const char *text
, int width
)
470 static char result
[MC_MAXPATHLEN
];
477 remain
= sizeof (result
);
478 length
= strlen (text
);
480 if ((int) length
> width
)
482 for (; pos
+ 1 <= (gsize
) width
/ 2 && remain
> 1; actual
++, pos
++, remain
--)
484 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
493 pos
+= length
- width
+ 1;
495 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
497 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
502 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
504 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
514 str_8bit_offset_to_pos (const char *text
, size_t length
)
521 str_8bit_column_to_pos (const char *text
, size_t pos
)
528 str_8bit_create_search_needle (const char *needle
, int case_sen
)
531 return (char *) needle
;
535 str_8bit_release_search_needle (char *needle
, int case_sen
)
542 str_8bit_strdown (const char *str
)
546 rets
= g_strdup (str
);
550 for (p
= rets
; *p
!= '\0'; p
++)
551 *p
= char_tolower (*p
);
558 str_8bit_search_first (const char *text
, const char *search
, int case_sen
)
565 fold_text
= (case_sen
) ? (char *) text
: str_8bit_strdown (text
);
566 fold_search
= (case_sen
) ? (char *) search
: str_8bit_strdown (search
);
568 match
= g_strstr_len (fold_text
, -1, fold_search
);
571 offsset
= match
- fold_text
;
572 match
= text
+ offsset
;
578 g_free (fold_search
);
585 str_8bit_search_last (const char *text
, const char *search
, int case_sen
)
592 fold_text
= (case_sen
) ? (char *) text
: str_8bit_strdown (text
);
593 fold_search
= (case_sen
) ? (char *) search
: str_8bit_strdown (search
);
595 match
= g_strrstr_len (fold_text
, -1, fold_search
);
598 offsset
= match
- fold_text
;
599 match
= text
+ offsset
;
605 g_free (fold_search
);
612 str_8bit_compare (const char *t1
, const char *t2
)
614 return strcmp (t1
, t2
);
618 str_8bit_ncompare (const char *t1
, const char *t2
)
620 return strncmp (t1
, t2
, min (strlen (t1
), strlen (t2
)));
624 str_8bit_casecmp (const char *s1
, const char *s2
)
628 #ifdef HAVE_STRCASECMP
629 g_return_val_if_fail (s1
!= NULL
, 0);
630 g_return_val_if_fail (s2
!= NULL
, 0);
632 return strcasecmp (s1
, s2
);
636 g_return_val_if_fail (s1
!= NULL
, 0);
637 g_return_val_if_fail (s2
!= NULL
, 0);
639 while (*s1
!= '\0' && *s2
!= '\0')
641 /* According to A. Cox, some platforms have islower's that
642 * don't work right on non-uppercase
644 c1
= isupper ((guchar
) * s1
) ? tolower ((guchar
) * s1
) : *s1
;
645 c2
= isupper ((guchar
) * s2
) ? tolower ((guchar
) * s2
) : *s2
;
652 return (((gint
) (guchar
) * s1
) - ((gint
) (guchar
) * s2
));
657 str_8bit_ncasecmp (const char *s1
, const char *s2
)
661 g_return_val_if_fail (s1
!= NULL
, 0);
662 g_return_val_if_fail (s2
!= NULL
, 0);
664 n
= min (strlen (s1
), strlen (s2
));
668 #ifdef HAVE_STRNCASECMP
669 return strncasecmp (s1
, s2
, n
);
673 while (n
!= 0 && *s1
!= '\0' && *s2
!= '\0')
676 /* According to A. Cox, some platforms have islower's that
677 * don't work right on non-uppercase
679 c1
= isupper ((guchar
) * s1
) ? tolower ((guchar
) * s1
) : *s1
;
680 c2
= isupper ((guchar
) * s2
) ? tolower ((guchar
) * s2
) : *s2
;
688 return (((gint
) (guchar
) * s1
) - ((gint
) (guchar
) * s2
));
695 str_8bit_prefix (const char *text
, const char *prefix
)
698 for (result
= 0; text
[result
] != '\0' && prefix
[result
] != '\0'
699 && text
[result
] == prefix
[result
]; result
++);
704 str_8bit_caseprefix (const char *text
, const char *prefix
)
707 for (result
= 0; text
[result
] != '\0' && prefix
[result
] != '\0'
708 && char_toupper (text
[result
]) == char_toupper (prefix
[result
]); result
++);
715 str_8bit_fix_string (char *text
)
721 str_8bit_create_key (const char *text
, int case_sen
)
723 return (case_sen
) ? (char *) text
: str_8bit_strdown (text
);
727 str_8bit_key_collate (const char *t1
, const char *t2
, int case_sen
)
730 return strcmp (t1
, t2
);
732 return strcoll (t1
, t2
);
736 str_8bit_release_key (char *key
, int case_sen
)
745 struct str_class result
;
747 result
.conv_gerror_message
= str_8bit_conv_gerror_message
;
748 result
.vfs_convert_to
= str_8bit_vfs_convert_to
;
749 result
.insert_replace_char
= str_8bit_insert_replace_char
;
750 result
.is_valid_string
= str_8bit_is_valid_string
;
751 result
.is_valid_char
= str_8bit_is_valid_char
;
752 result
.cnext_char
= str_8bit_cnext_char
;
753 result
.cprev_char
= str_8bit_cprev_char
;
754 result
.cnext_char_safe
= str_8bit_cnext_char
;
755 result
.cprev_char_safe
= str_8bit_cprev_char
;
756 result
.cnext_noncomb_char
= str_8bit_cnext_noncomb_char
;
757 result
.cprev_noncomb_char
= str_8bit_cprev_noncomb_char
;
758 result
.char_isspace
= str_8bit_isspace
;
759 result
.char_ispunct
= str_8bit_ispunct
;
760 result
.char_isalnum
= str_8bit_isalnum
;
761 result
.char_isdigit
= str_8bit_isdigit
;
762 result
.char_isprint
= str_8bit_isprint
;
763 result
.char_iscombiningmark
= str_8bit_iscombiningmark
;
764 result
.char_toupper
= str_8bit_toupper
;
765 result
.char_tolower
= str_8bit_tolower
;
766 result
.length
= str_8bit_length
;
767 result
.length2
= str_8bit_length2
;
768 result
.length_noncomb
= str_8bit_length
;
769 result
.fix_string
= str_8bit_fix_string
;
770 result
.term_form
= str_8bit_term_form
;
771 result
.fit_to_term
= str_8bit_fit_to_term
;
772 result
.term_trim
= str_8bit_term_trim
;
773 result
.term_width2
= str_8bit_term_width2
;
774 result
.term_width1
= str_8bit_term_width1
;
775 result
.term_char_width
= str_8bit_term_char_width
;
776 result
.term_substring
= str_8bit_term_substring
;
777 result
.trunc
= str_8bit_trunc
;
778 result
.offset_to_pos
= str_8bit_offset_to_pos
;
779 result
.column_to_pos
= str_8bit_column_to_pos
;
780 result
.create_search_needle
= str_8bit_create_search_needle
;
781 result
.release_search_needle
= str_8bit_release_search_needle
;
782 result
.search_first
= str_8bit_search_first
;
783 result
.search_last
= str_8bit_search_last
;
784 result
.compare
= str_8bit_compare
;
785 result
.ncompare
= str_8bit_ncompare
;
786 result
.casecmp
= str_8bit_casecmp
;
787 result
.ncasecmp
= str_8bit_ncasecmp
;
788 result
.prefix
= str_8bit_prefix
;
789 result
.caseprefix
= str_8bit_caseprefix
;
790 result
.create_key
= str_8bit_create_key
;
791 result
.create_key_for_filename
= str_8bit_create_key
;
792 result
.key_collate
= str_8bit_key_collate
;
793 result
.release_key
= str_8bit_release_key
;