4 Copyright (C) 2007, 2011
5 The Free Software Foundation, Inc.
10 The file_date routine is mostly from GNU's fileutils package,
11 written by Richard Stallman and David MacKenzie.
13 This file is part of the Midnight Commander.
15 The Midnight Commander is free software: you can redistribute it
16 and/or modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation, either version 3 of the License,
18 or (at your option) any later version.
20 The Midnight Commander is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program. If not, see <http://www.gnu.org/licenses/>.
34 #include "lib/global.h"
35 #include "lib/strutil.h"
37 /* functions for singlebyte encodings, all characters have width 1
38 * using standard system functions
39 * there are only small differences between functions in strutil8bit.c
43 static const char replch
= '?';
46 * Inlines to equalize 'char' signedness for single 'char' encodings.
48 * isspace((unsigned char)c);
53 #define DECLARE_CTYPE_WRAPPER(func_name) \
54 static inline int char_##func_name(char c) \
56 return func_name((int)(unsigned char)c); \
60 DECLARE_CTYPE_WRAPPER (isalnum
)
61 DECLARE_CTYPE_WRAPPER (isalpha
)
62 DECLARE_CTYPE_WRAPPER (isascii
)
63 DECLARE_CTYPE_WRAPPER (isblank
)
64 DECLARE_CTYPE_WRAPPER (iscntrl
)
65 DECLARE_CTYPE_WRAPPER (isdigit
)
66 DECLARE_CTYPE_WRAPPER (isgraph
)
67 DECLARE_CTYPE_WRAPPER (islower
)
68 DECLARE_CTYPE_WRAPPER (isprint
)
69 DECLARE_CTYPE_WRAPPER (ispunct
)
70 DECLARE_CTYPE_WRAPPER (isspace
)
71 DECLARE_CTYPE_WRAPPER (isupper
)
72 DECLARE_CTYPE_WRAPPER (isxdigit
)
73 DECLARE_CTYPE_WRAPPER (toupper
)
74 DECLARE_CTYPE_WRAPPER (tolower
)
78 str_8bit_insert_replace_char (GString
* buffer
)
80 g_string_append_c (buffer
, replch
);
84 str_8bit_is_valid_string (const char *text
)
91 str_8bit_is_valid_char (const char *ch
, size_t size
)
99 str_8bit_cnext_char (const char **text
)
105 str_8bit_cprev_char (const char **text
)
111 str_8bit_cnext_noncomb_char (const char **text
)
113 if (*text
[0] != '\0')
123 str_8bit_cprev_noncomb_char (const char **text
, const char *begin
)
125 if ((*text
) != begin
)
135 str_8bit_isspace (const char *text
)
137 return char_isspace (text
[0]);
141 str_8bit_ispunct (const char *text
)
143 return char_ispunct (text
[0]);
147 str_8bit_isalnum (const char *text
)
149 return char_isalnum (text
[0]);
153 str_8bit_isdigit (const char *text
)
155 return char_isdigit (text
[0]);
159 str_8bit_isprint (const char *text
)
161 return char_isprint (text
[0]);
165 str_8bit_iscombiningmark (const char *text
)
172 str_8bit_toupper (const char *text
, char **out
, size_t * remain
)
176 (*out
)[0] = char_toupper (text
[0]);
183 str_8bit_tolower (const char *text
, char **out
, size_t * remain
)
187 (*out
)[0] = char_tolower (text
[0]);
194 str_8bit_length (const char *text
)
196 return strlen (text
);
200 str_8bit_length2 (const char *text
, int size
)
202 return (size
>= 0) ? min (strlen (text
), (gsize
) size
) : strlen (text
);
206 str_8bit_conv_gerror_message (GError
* error
, const char *def_msg
)
211 /* glib messages are in UTF-8 charset */
212 conv
= str_crt_conv_from ("UTF-8");
214 if (conv
== INVALID_CONV
)
215 ret
= g_strdup (def_msg
!= NULL
? def_msg
: "");
220 buf
= g_string_new ("");
222 if (str_convert (conv
, error
->message
, buf
) != ESTR_FAILURE
)
225 g_string_free (buf
, FALSE
);
229 ret
= g_strdup (def_msg
!= NULL
? def_msg
: "");
230 g_string_free (buf
, TRUE
);
233 str_close_conv (conv
);
240 str_8bit_vfs_convert_to (GIConv coder
, const char *string
, int size
, GString
* buffer
)
244 if (coder
== str_cnv_not_convert
)
246 g_string_append_len (buffer
, string
, size
);
247 result
= ESTR_SUCCESS
;
250 result
= str_nconvert (coder
, (char *) string
, size
, buffer
);
257 str_8bit_term_form (const char *text
)
259 static char result
[BUF_MEDIUM
];
266 remain
= sizeof (result
);
267 length
= strlen (text
);
269 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
271 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
279 str_8bit_fit_to_term (const char *text
, int width
, align_crt_t just_mode
)
281 static char result
[BUF_MEDIUM
];
288 length
= strlen (text
);
290 remain
= sizeof (result
);
292 if ((int) length
<= width
)
295 switch (HIDE_FIT (just_mode
))
299 ident
= (width
- length
) / 2;
302 ident
= width
- length
;
306 if ((int) remain
<= ident
)
308 memset (actual
, ' ', ident
);
312 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
314 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
316 if (width
- length
- ident
> 0)
318 if (remain
<= width
- length
- ident
)
320 memset (actual
, ' ', width
- length
- ident
);
321 actual
+= width
- length
- ident
;
326 if (IS_FIT (just_mode
))
328 for (; pos
+ 1 <= (gsize
) width
/ 2 && remain
> 1; actual
++, pos
++, remain
--)
331 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
340 pos
+= length
- width
+ 1;
342 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
344 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
350 switch (HIDE_FIT (just_mode
))
353 ident
= (length
- width
) / 2;
356 ident
= length
- width
;
361 for (; pos
< (gsize
) (ident
+ width
) && remain
> 1; pos
++, actual
++, remain
--)
364 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
375 str_8bit_term_trim (const char *text
, int width
)
377 static char result
[BUF_MEDIUM
];
383 length
= strlen (text
);
385 remain
= sizeof (result
);
389 if (width
< (int) length
)
393 memset (actual
, '.', width
);
398 memset (actual
, '.', 3);
402 pos
+= length
- width
+ 3;
404 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
405 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
410 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
411 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
420 str_8bit_term_width2 (const char *text
, size_t length
)
422 return (length
!= (size_t) (-1)) ? min (strlen (text
), length
) : strlen (text
);
426 str_8bit_term_width1 (const char *text
)
428 return str_8bit_term_width2 (text
, (size_t) (-1));
432 str_8bit_term_char_width (const char *text
)
439 str_8bit_term_substring (const char *text
, int start
, int width
)
441 static char result
[BUF_MEDIUM
];
448 remain
= sizeof (result
);
449 length
= strlen (text
);
451 if (start
< (int) length
)
454 for (; pos
< length
&& width
> 0 && remain
> 1; pos
++, width
--, actual
++, remain
--)
457 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
461 for (; width
> 0 && remain
> 1; actual
++, remain
--, width
--)
471 str_8bit_trunc (const char *text
, int width
)
473 static char result
[MC_MAXPATHLEN
];
480 remain
= sizeof (result
);
481 length
= strlen (text
);
483 if ((int) length
> width
)
485 for (; pos
+ 1 <= (gsize
) width
/ 2 && remain
> 1; actual
++, pos
++, remain
--)
487 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
496 pos
+= length
- width
+ 1;
498 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
500 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
505 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
507 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
517 str_8bit_offset_to_pos (const char *text
, size_t length
)
524 str_8bit_column_to_pos (const char *text
, size_t pos
)
531 str_8bit_create_search_needle (const char *needle
, int case_sen
)
534 return (char *) needle
;
538 str_8bit_release_search_needle (char *needle
, int case_sen
)
545 str_8bit_strdown (const char *str
)
549 rets
= g_strdup (str
);
553 for (p
= rets
; *p
!= '\0'; p
++)
554 *p
= char_tolower (*p
);
561 str_8bit_search_first (const char *text
, const char *search
, int case_sen
)
568 fold_text
= (case_sen
) ? (char *) text
: str_8bit_strdown (text
);
569 fold_search
= (case_sen
) ? (char *) search
: str_8bit_strdown (search
);
571 match
= g_strstr_len (fold_text
, -1, fold_search
);
574 offsset
= match
- fold_text
;
575 match
= text
+ offsset
;
581 g_free (fold_search
);
588 str_8bit_search_last (const char *text
, const char *search
, int case_sen
)
595 fold_text
= (case_sen
) ? (char *) text
: str_8bit_strdown (text
);
596 fold_search
= (case_sen
) ? (char *) search
: str_8bit_strdown (search
);
598 match
= g_strrstr_len (fold_text
, -1, fold_search
);
601 offsset
= match
- fold_text
;
602 match
= text
+ offsset
;
608 g_free (fold_search
);
615 str_8bit_compare (const char *t1
, const char *t2
)
617 return strcmp (t1
, t2
);
621 str_8bit_ncompare (const char *t1
, const char *t2
)
623 return strncmp (t1
, t2
, min (strlen (t1
), strlen (t2
)));
627 str_8bit_casecmp (const char *s1
, const char *s2
)
631 #ifdef HAVE_STRCASECMP
632 g_return_val_if_fail (s1
!= NULL
, 0);
633 g_return_val_if_fail (s2
!= NULL
, 0);
635 return strcasecmp (s1
, s2
);
639 g_return_val_if_fail (s1
!= NULL
, 0);
640 g_return_val_if_fail (s2
!= NULL
, 0);
642 while (*s1
!= '\0' && *s2
!= '\0')
644 /* According to A. Cox, some platforms have islower's that
645 * don't work right on non-uppercase
647 c1
= isupper ((guchar
) * s1
) ? tolower ((guchar
) * s1
) : *s1
;
648 c2
= isupper ((guchar
) * s2
) ? tolower ((guchar
) * s2
) : *s2
;
655 return (((gint
) (guchar
) * s1
) - ((gint
) (guchar
) * s2
));
660 str_8bit_ncasecmp (const char *s1
, const char *s2
)
664 g_return_val_if_fail (s1
!= NULL
, 0);
665 g_return_val_if_fail (s2
!= NULL
, 0);
667 n
= min (strlen (s1
), strlen (s2
));
671 #ifdef HAVE_STRNCASECMP
672 return strncasecmp (s1
, s2
, n
);
676 while (n
!= 0 && *s1
!= '\0' && *s2
!= '\0')
679 /* According to A. Cox, some platforms have islower's that
680 * don't work right on non-uppercase
682 c1
= isupper ((guchar
) * s1
) ? tolower ((guchar
) * s1
) : *s1
;
683 c2
= isupper ((guchar
) * s2
) ? tolower ((guchar
) * s2
) : *s2
;
691 return (((gint
) (guchar
) * s1
) - ((gint
) (guchar
) * s2
));
698 str_8bit_prefix (const char *text
, const char *prefix
)
701 for (result
= 0; text
[result
] != '\0' && prefix
[result
] != '\0'
702 && text
[result
] == prefix
[result
]; result
++);
707 str_8bit_caseprefix (const char *text
, const char *prefix
)
710 for (result
= 0; text
[result
] != '\0' && prefix
[result
] != '\0'
711 && char_toupper (text
[result
]) == char_toupper (prefix
[result
]); result
++);
718 str_8bit_fix_string (char *text
)
724 str_8bit_create_key (const char *text
, int case_sen
)
726 return (case_sen
) ? (char *) text
: str_8bit_strdown (text
);
730 str_8bit_key_collate (const char *t1
, const char *t2
, int case_sen
)
733 return strcmp (t1
, t2
);
735 return strcoll (t1
, t2
);
739 str_8bit_release_key (char *key
, int case_sen
)
748 struct str_class result
;
750 result
.conv_gerror_message
= str_8bit_conv_gerror_message
;
751 result
.vfs_convert_to
= str_8bit_vfs_convert_to
;
752 result
.insert_replace_char
= str_8bit_insert_replace_char
;
753 result
.is_valid_string
= str_8bit_is_valid_string
;
754 result
.is_valid_char
= str_8bit_is_valid_char
;
755 result
.cnext_char
= str_8bit_cnext_char
;
756 result
.cprev_char
= str_8bit_cprev_char
;
757 result
.cnext_char_safe
= str_8bit_cnext_char
;
758 result
.cprev_char_safe
= str_8bit_cprev_char
;
759 result
.cnext_noncomb_char
= str_8bit_cnext_noncomb_char
;
760 result
.cprev_noncomb_char
= str_8bit_cprev_noncomb_char
;
761 result
.isspace
= str_8bit_isspace
;
762 result
.ispunct
= str_8bit_ispunct
;
763 result
.isalnum
= str_8bit_isalnum
;
764 result
.isdigit
= str_8bit_isdigit
;
765 result
.isprint
= str_8bit_isprint
;
766 result
.iscombiningmark
= str_8bit_iscombiningmark
;
767 result
.toupper
= str_8bit_toupper
;
768 result
.tolower
= str_8bit_tolower
;
769 result
.length
= str_8bit_length
;
770 result
.length2
= str_8bit_length2
;
771 result
.length_noncomb
= str_8bit_length
;
772 result
.fix_string
= str_8bit_fix_string
;
773 result
.term_form
= str_8bit_term_form
;
774 result
.fit_to_term
= str_8bit_fit_to_term
;
775 result
.term_trim
= str_8bit_term_trim
;
776 result
.term_width2
= str_8bit_term_width2
;
777 result
.term_width1
= str_8bit_term_width1
;
778 result
.term_char_width
= str_8bit_term_char_width
;
779 result
.term_substring
= str_8bit_term_substring
;
780 result
.trunc
= str_8bit_trunc
;
781 result
.offset_to_pos
= str_8bit_offset_to_pos
;
782 result
.column_to_pos
= str_8bit_column_to_pos
;
783 result
.create_search_needle
= str_8bit_create_search_needle
;
784 result
.release_search_needle
= str_8bit_release_search_needle
;
785 result
.search_first
= str_8bit_search_first
;
786 result
.search_last
= str_8bit_search_last
;
787 result
.compare
= str_8bit_compare
;
788 result
.ncompare
= str_8bit_ncompare
;
789 result
.casecmp
= str_8bit_casecmp
;
790 result
.ncasecmp
= str_8bit_ncasecmp
;
791 result
.prefix
= str_8bit_prefix
;
792 result
.caseprefix
= str_8bit_caseprefix
;
793 result
.create_key
= str_8bit_create_key
;
794 result
.create_key_for_filename
= str_8bit_create_key
;
795 result
.key_collate
= str_8bit_key_collate
;
796 result
.release_key
= str_8bit_release_key
;