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
;
322 remain
-= width
- length
- ident
;
327 if (IS_FIT (just_mode
))
329 for (; pos
+ 1 <= (gsize
) width
/ 2 && remain
> 1; actual
++, pos
++, remain
--)
332 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
341 pos
+= length
- width
+ 1;
343 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
345 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
351 switch (HIDE_FIT (just_mode
))
354 ident
= (length
- width
) / 2;
357 ident
= length
- width
;
362 for (; pos
< (gsize
) (ident
+ width
) && remain
> 1; pos
++, actual
++, remain
--)
365 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
376 str_8bit_term_trim (const char *text
, int width
)
378 static char result
[BUF_MEDIUM
];
384 length
= strlen (text
);
386 remain
= sizeof (result
);
390 if (width
< (int) length
)
394 memset (actual
, '.', width
);
400 memset (actual
, '.', 3);
404 pos
+= length
- width
+ 3;
406 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
407 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
412 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
413 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
422 str_8bit_term_width2 (const char *text
, size_t length
)
424 return (length
!= (size_t) (-1)) ? min (strlen (text
), length
) : strlen (text
);
428 str_8bit_term_width1 (const char *text
)
430 return str_8bit_term_width2 (text
, (size_t) (-1));
434 str_8bit_term_char_width (const char *text
)
441 str_8bit_term_substring (const char *text
, int start
, int width
)
443 static char result
[BUF_MEDIUM
];
450 remain
= sizeof (result
);
451 length
= strlen (text
);
453 if (start
< (int) length
)
456 for (; pos
< length
&& width
> 0 && remain
> 1; pos
++, width
--, actual
++, remain
--)
459 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
463 for (; width
> 0 && remain
> 1; actual
++, remain
--, width
--)
473 str_8bit_trunc (const char *text
, int width
)
475 static char result
[MC_MAXPATHLEN
];
482 remain
= sizeof (result
);
483 length
= strlen (text
);
485 if ((int) length
> width
)
487 for (; pos
+ 1 <= (gsize
) width
/ 2 && remain
> 1; actual
++, pos
++, remain
--)
489 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
498 pos
+= length
- width
+ 1;
500 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
502 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
507 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
509 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
519 str_8bit_offset_to_pos (const char *text
, size_t length
)
526 str_8bit_column_to_pos (const char *text
, size_t pos
)
533 str_8bit_create_search_needle (const char *needle
, int case_sen
)
536 return (char *) needle
;
540 str_8bit_release_search_needle (char *needle
, int case_sen
)
547 str_8bit_strdown (const char *str
)
551 rets
= g_strdup (str
);
555 for (p
= rets
; *p
!= '\0'; p
++)
556 *p
= char_tolower (*p
);
563 str_8bit_search_first (const char *text
, const char *search
, int case_sen
)
570 fold_text
= (case_sen
) ? (char *) text
: str_8bit_strdown (text
);
571 fold_search
= (case_sen
) ? (char *) search
: str_8bit_strdown (search
);
573 match
= g_strstr_len (fold_text
, -1, fold_search
);
576 offsset
= match
- fold_text
;
577 match
= text
+ offsset
;
583 g_free (fold_search
);
590 str_8bit_search_last (const char *text
, const char *search
, int case_sen
)
597 fold_text
= (case_sen
) ? (char *) text
: str_8bit_strdown (text
);
598 fold_search
= (case_sen
) ? (char *) search
: str_8bit_strdown (search
);
600 match
= g_strrstr_len (fold_text
, -1, fold_search
);
603 offsset
= match
- fold_text
;
604 match
= text
+ offsset
;
610 g_free (fold_search
);
617 str_8bit_compare (const char *t1
, const char *t2
)
619 return strcmp (t1
, t2
);
623 str_8bit_ncompare (const char *t1
, const char *t2
)
625 return strncmp (t1
, t2
, min (strlen (t1
), strlen (t2
)));
629 str_8bit_casecmp (const char *s1
, const char *s2
)
633 #ifdef HAVE_STRCASECMP
634 g_return_val_if_fail (s1
!= NULL
, 0);
635 g_return_val_if_fail (s2
!= NULL
, 0);
637 return strcasecmp (s1
, s2
);
641 g_return_val_if_fail (s1
!= NULL
, 0);
642 g_return_val_if_fail (s2
!= NULL
, 0);
644 while (*s1
!= '\0' && *s2
!= '\0')
646 /* According to A. Cox, some platforms have islower's that
647 * don't work right on non-uppercase
649 c1
= isupper ((guchar
) * s1
) ? tolower ((guchar
) * s1
) : *s1
;
650 c2
= isupper ((guchar
) * s2
) ? tolower ((guchar
) * s2
) : *s2
;
657 return (((gint
) (guchar
) * s1
) - ((gint
) (guchar
) * s2
));
662 str_8bit_ncasecmp (const char *s1
, const char *s2
)
666 g_return_val_if_fail (s1
!= NULL
, 0);
667 g_return_val_if_fail (s2
!= NULL
, 0);
669 n
= min (strlen (s1
), strlen (s2
));
673 #ifdef HAVE_STRNCASECMP
674 return strncasecmp (s1
, s2
, n
);
678 while (n
!= 0 && *s1
!= '\0' && *s2
!= '\0')
681 /* According to A. Cox, some platforms have islower's that
682 * don't work right on non-uppercase
684 c1
= isupper ((guchar
) * s1
) ? tolower ((guchar
) * s1
) : *s1
;
685 c2
= isupper ((guchar
) * s2
) ? tolower ((guchar
) * s2
) : *s2
;
693 return (((gint
) (guchar
) * s1
) - ((gint
) (guchar
) * s2
));
700 str_8bit_prefix (const char *text
, const char *prefix
)
703 for (result
= 0; text
[result
] != '\0' && prefix
[result
] != '\0'
704 && text
[result
] == prefix
[result
]; result
++);
709 str_8bit_caseprefix (const char *text
, const char *prefix
)
712 for (result
= 0; text
[result
] != '\0' && prefix
[result
] != '\0'
713 && char_toupper (text
[result
]) == char_toupper (prefix
[result
]); result
++);
720 str_8bit_fix_string (char *text
)
726 str_8bit_create_key (const char *text
, int case_sen
)
728 return (case_sen
) ? (char *) text
: str_8bit_strdown (text
);
732 str_8bit_key_collate (const char *t1
, const char *t2
, int case_sen
)
735 return strcmp (t1
, t2
);
737 return strcoll (t1
, t2
);
741 str_8bit_release_key (char *key
, int case_sen
)
750 struct str_class result
;
752 result
.conv_gerror_message
= str_8bit_conv_gerror_message
;
753 result
.vfs_convert_to
= str_8bit_vfs_convert_to
;
754 result
.insert_replace_char
= str_8bit_insert_replace_char
;
755 result
.is_valid_string
= str_8bit_is_valid_string
;
756 result
.is_valid_char
= str_8bit_is_valid_char
;
757 result
.cnext_char
= str_8bit_cnext_char
;
758 result
.cprev_char
= str_8bit_cprev_char
;
759 result
.cnext_char_safe
= str_8bit_cnext_char
;
760 result
.cprev_char_safe
= str_8bit_cprev_char
;
761 result
.cnext_noncomb_char
= str_8bit_cnext_noncomb_char
;
762 result
.cprev_noncomb_char
= str_8bit_cprev_noncomb_char
;
763 result
.isspace
= str_8bit_isspace
;
764 result
.ispunct
= str_8bit_ispunct
;
765 result
.isalnum
= str_8bit_isalnum
;
766 result
.isdigit
= str_8bit_isdigit
;
767 result
.isprint
= str_8bit_isprint
;
768 result
.iscombiningmark
= str_8bit_iscombiningmark
;
769 result
.toupper
= str_8bit_toupper
;
770 result
.tolower
= str_8bit_tolower
;
771 result
.length
= str_8bit_length
;
772 result
.length2
= str_8bit_length2
;
773 result
.length_noncomb
= str_8bit_length
;
774 result
.fix_string
= str_8bit_fix_string
;
775 result
.term_form
= str_8bit_term_form
;
776 result
.fit_to_term
= str_8bit_fit_to_term
;
777 result
.term_trim
= str_8bit_term_trim
;
778 result
.term_width2
= str_8bit_term_width2
;
779 result
.term_width1
= str_8bit_term_width1
;
780 result
.term_char_width
= str_8bit_term_char_width
;
781 result
.term_substring
= str_8bit_term_substring
;
782 result
.trunc
= str_8bit_trunc
;
783 result
.offset_to_pos
= str_8bit_offset_to_pos
;
784 result
.column_to_pos
= str_8bit_column_to_pos
;
785 result
.create_search_needle
= str_8bit_create_search_needle
;
786 result
.release_search_needle
= str_8bit_release_search_needle
;
787 result
.search_first
= str_8bit_search_first
;
788 result
.search_last
= str_8bit_search_last
;
789 result
.compare
= str_8bit_compare
;
790 result
.ncompare
= str_8bit_ncompare
;
791 result
.casecmp
= str_8bit_casecmp
;
792 result
.ncasecmp
= str_8bit_ncasecmp
;
793 result
.prefix
= str_8bit_prefix
;
794 result
.caseprefix
= str_8bit_caseprefix
;
795 result
.create_key
= str_8bit_create_key
;
796 result
.create_key_for_filename
= str_8bit_create_key
;
797 result
.key_collate
= str_8bit_key_collate
;
798 result
.release_key
= str_8bit_release_key
;