4 Copyright (C) 2007-2024
5 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 /*** global variables ****************************************************************************/
42 /*** file scope macro definitions ****************************************************************/
45 * Inlines to equalize 'char' signedness for single 'char' encodings.
47 * isspace ((unsigned char) c);
51 #define DECLARE_CTYPE_WRAPPER(func_name) \
52 static inline int char_##func_name(char c) \
54 return func_name((int)(unsigned char)c); \
57 /*** file scope type declarations ****************************************************************/
59 /*** forward declarations (file scope functions) *************************************************/
61 /*** file scope variables ************************************************************************/
63 static const char replch
= '?';
65 /* --------------------------------------------------------------------------------------------- */
66 /*** file scope functions ************************************************************************/
67 /* --------------------------------------------------------------------------------------------- */
70 DECLARE_CTYPE_WRAPPER (isalnum
)
71 DECLARE_CTYPE_WRAPPER (isdigit
)
72 DECLARE_CTYPE_WRAPPER (isprint
)
73 DECLARE_CTYPE_WRAPPER (ispunct
)
74 DECLARE_CTYPE_WRAPPER (isspace
)
75 DECLARE_CTYPE_WRAPPER (toupper
)
76 DECLARE_CTYPE_WRAPPER (tolower
)
79 /* --------------------------------------------------------------------------------------------- */
82 str_8bit_insert_replace_char (GString
* buffer
)
84 g_string_append_c (buffer
, replch
);
87 /* --------------------------------------------------------------------------------------------- */
90 str_8bit_is_valid_string (const char *text
)
96 /* --------------------------------------------------------------------------------------------- */
99 str_8bit_is_valid_char (const char *ch
, size_t size
)
106 /* --------------------------------------------------------------------------------------------- */
109 str_8bit_cnext_char (const char **text
)
114 /* --------------------------------------------------------------------------------------------- */
117 str_8bit_cprev_char (const char **text
)
122 /* --------------------------------------------------------------------------------------------- */
125 str_8bit_cnext_noncomb_char (const char **text
)
127 if (*text
[0] == '\0')
134 /* --------------------------------------------------------------------------------------------- */
137 str_8bit_cprev_noncomb_char (const char **text
, const char *begin
)
139 if ((*text
) == begin
)
146 /* --------------------------------------------------------------------------------------------- */
149 str_8bit_isspace (const char *text
)
151 return char_isspace (text
[0]) != 0;
154 /* --------------------------------------------------------------------------------------------- */
157 str_8bit_ispunct (const char *text
)
159 return char_ispunct (text
[0]) != 0;
162 /* --------------------------------------------------------------------------------------------- */
165 str_8bit_isalnum (const char *text
)
167 return char_isalnum (text
[0]) != 0;
170 /* --------------------------------------------------------------------------------------------- */
173 str_8bit_isdigit (const char *text
)
175 return char_isdigit (text
[0]) != 0;
178 /* --------------------------------------------------------------------------------------------- */
181 str_8bit_isprint (const char *text
)
183 return char_isprint (text
[0]) != 0;
186 /* --------------------------------------------------------------------------------------------- */
189 str_8bit_iscombiningmark (const char *text
)
195 /* --------------------------------------------------------------------------------------------- */
198 str_8bit_toupper (const char *text
, char **out
, size_t * remain
)
203 (*out
)[0] = char_toupper (text
[0]);
209 /* --------------------------------------------------------------------------------------------- */
212 str_8bit_tolower (const char *text
, char **out
, size_t * remain
)
217 (*out
)[0] = char_tolower (text
[0]);
223 /* --------------------------------------------------------------------------------------------- */
226 str_8bit_length (const char *text
)
228 return strlen (text
);
231 /* --------------------------------------------------------------------------------------------- */
234 str_8bit_length2 (const char *text
, int size
)
236 return (size
>= 0) ? MIN (strlen (text
), (gsize
) size
) : strlen (text
);
239 /* --------------------------------------------------------------------------------------------- */
242 str_8bit_conv_gerror_message (GError
* mcerror
, const char *def_msg
)
247 /* glib messages are in UTF-8 charset */
248 conv
= str_crt_conv_from ("UTF-8");
250 if (conv
== INVALID_CONV
)
251 ret
= g_strdup (def_msg
!= NULL
? def_msg
: "");
256 buf
= g_string_new ("");
258 if (str_convert (conv
, mcerror
->message
, buf
) != ESTR_FAILURE
)
259 ret
= g_string_free (buf
, FALSE
);
262 ret
= g_strdup (def_msg
!= NULL
? def_msg
: "");
263 g_string_free (buf
, TRUE
);
266 str_close_conv (conv
);
272 /* --------------------------------------------------------------------------------------------- */
275 str_8bit_vfs_convert_to (GIConv coder
, const char *string
, int size
, GString
* buffer
)
277 estr_t result
= ESTR_SUCCESS
;
279 if (coder
== str_cnv_not_convert
)
280 g_string_append_len (buffer
, string
, size
);
282 result
= str_nconvert (coder
, string
, size
, buffer
);
287 /* --------------------------------------------------------------------------------------------- */
290 str_8bit_term_form (const char *text
)
292 static char result
[BUF_MEDIUM
];
299 remain
= sizeof (result
);
300 length
= strlen (text
);
302 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
303 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
309 /* --------------------------------------------------------------------------------------------- */
312 str_8bit_fit_to_term (const char *text
, int width
, align_crt_t just_mode
)
314 static char result
[BUF_MEDIUM
];
321 length
= strlen (text
);
323 remain
= sizeof (result
);
325 if ((int) length
<= width
)
327 switch (HIDE_FIT (just_mode
))
331 ident
= (width
- length
) / 2;
334 ident
= width
- length
;
340 if ((int) remain
<= ident
)
342 memset (actual
, ' ', ident
);
346 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
347 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
349 if (width
- length
- ident
> 0)
351 if (remain
<= width
- length
- ident
)
353 memset (actual
, ' ', width
- length
- ident
);
354 actual
+= width
- length
- ident
;
357 else if (IS_FIT (just_mode
))
359 for (; pos
+ 1 <= (gsize
) width
/ 2 && remain
> 1; actual
++, pos
++, remain
--)
360 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
368 pos
+= length
- width
+ 1;
369 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
370 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
374 switch (HIDE_FIT (just_mode
))
377 ident
= (length
- width
) / 2;
380 ident
= length
- width
;
387 for (; pos
< (gsize
) (ident
+ width
) && remain
> 1; pos
++, actual
++, remain
--)
388 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
392 if (actual
>= result
+ sizeof (result
))
393 actual
= result
+ sizeof (result
) - 1;
398 /* --------------------------------------------------------------------------------------------- */
401 str_8bit_term_trim (const char *text
, int width
)
403 static char result
[BUF_MEDIUM
];
408 length
= strlen (text
);
410 remain
= sizeof (result
);
416 if (width
>= (int) length
)
418 for (pos
= 0; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
419 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
423 memset (actual
, '.', width
);
428 memset (actual
, '.', 3);
432 for (pos
= length
- width
+ 3; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
433 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
441 /* --------------------------------------------------------------------------------------------- */
444 str_8bit_term_width2 (const char *text
, size_t length
)
446 return (length
!= (size_t) (-1)) ? MIN (strlen (text
), length
) : strlen (text
);
449 /* --------------------------------------------------------------------------------------------- */
452 str_8bit_term_width1 (const char *text
)
454 return str_8bit_term_width2 (text
, (size_t) (-1));
457 /* --------------------------------------------------------------------------------------------- */
460 str_8bit_term_char_width (const char *text
)
466 /* --------------------------------------------------------------------------------------------- */
469 str_8bit_term_substring (const char *text
, int start
, int width
)
471 static char result
[BUF_MEDIUM
];
477 remain
= sizeof (result
);
478 length
= strlen (text
);
480 if (start
< (int) length
)
484 for (pos
= start
; pos
< length
&& width
> 0 && remain
> 1;
485 pos
++, width
--, actual
++, remain
--)
486 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
489 for (; width
> 0 && remain
> 1; actual
++, remain
--, width
--)
496 /* --------------------------------------------------------------------------------------------- */
499 str_8bit_trunc (const char *text
, int width
)
501 static char result
[MC_MAXPATHLEN
];
508 remain
= sizeof (result
);
509 length
= strlen (text
);
511 if ((int) length
> width
)
513 for (; pos
+ 1 <= (gsize
) width
/ 2 && remain
> 1; actual
++, pos
++, remain
--)
514 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
522 pos
+= length
- width
+ 1;
523 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
524 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
528 for (; pos
< length
&& remain
> 1; pos
++, actual
++, remain
--)
529 actual
[0] = char_isprint (text
[pos
]) ? text
[pos
] : '.';
537 /* --------------------------------------------------------------------------------------------- */
540 str_8bit_offset_to_pos (const char *text
, size_t length
)
546 /* --------------------------------------------------------------------------------------------- */
549 str_8bit_column_to_pos (const char *text
, size_t pos
)
555 /* --------------------------------------------------------------------------------------------- */
558 str_8bit_create_search_needle (const char *needle
, gboolean case_sen
)
561 return (char *) needle
;
564 /* --------------------------------------------------------------------------------------------- */
567 str_8bit_release_search_needle (char *needle
, gboolean case_sen
)
573 /* --------------------------------------------------------------------------------------------- */
576 str_8bit_strdown (const char *str
)
583 rets
= g_strdup (str
);
585 for (p
= rets
; *p
!= '\0'; p
++)
586 *p
= char_tolower (*p
);
591 /* --------------------------------------------------------------------------------------------- */
594 str_8bit_search_first (const char *text
, const char *search
, gboolean case_sen
)
600 fold_text
= case_sen
? (char *) text
: str_8bit_strdown (text
);
601 fold_search
= case_sen
? (char *) search
: str_8bit_strdown (search
);
603 match
= g_strstr_len (fold_text
, -1, fold_search
);
608 offset
= match
- fold_text
;
609 match
= text
+ offset
;
615 g_free (fold_search
);
621 /* --------------------------------------------------------------------------------------------- */
624 str_8bit_search_last (const char *text
, const char *search
, gboolean case_sen
)
630 fold_text
= case_sen
? (char *) text
: str_8bit_strdown (text
);
631 fold_search
= case_sen
? (char *) search
: str_8bit_strdown (search
);
633 match
= g_strrstr_len (fold_text
, -1, fold_search
);
638 offset
= match
- fold_text
;
639 match
= text
+ offset
;
645 g_free (fold_search
);
651 /* --------------------------------------------------------------------------------------------- */
654 str_8bit_compare (const char *t1
, const char *t2
)
656 return strcmp (t1
, t2
);
659 /* --------------------------------------------------------------------------------------------- */
662 str_8bit_ncompare (const char *t1
, const char *t2
)
664 return strncmp (t1
, t2
, MIN (strlen (t1
), strlen (t2
)));
667 /* --------------------------------------------------------------------------------------------- */
670 str_8bit_casecmp (const char *s1
, const char *s2
)
674 #ifdef HAVE_STRCASECMP
675 g_return_val_if_fail (s1
!= NULL
, 0);
676 g_return_val_if_fail (s2
!= NULL
, 0);
678 return strcasecmp (s1
, s2
);
681 g_return_val_if_fail (s1
!= NULL
, 0);
682 g_return_val_if_fail (s2
!= NULL
, 0);
684 for (; *s1
!= '\0' && *s2
!= '\0'; s1
++, s2
++)
688 /* According to A. Cox, some platforms have islower's that
689 * don't work right on non-uppercase
691 c1
= isupper ((guchar
) * s1
) ? tolower ((guchar
) * s1
) : *s1
;
692 c2
= isupper ((guchar
) * s2
) ? tolower ((guchar
) * s2
) : *s2
;
697 return (((gint
) (guchar
) * s1
) - ((gint
) (guchar
) * s2
));
701 /* --------------------------------------------------------------------------------------------- */
704 str_8bit_ncasecmp (const char *s1
, const char *s2
)
708 g_return_val_if_fail (s1
!= NULL
, 0);
709 g_return_val_if_fail (s2
!= NULL
, 0);
711 n
= MIN (strlen (s1
), strlen (s2
));
715 #ifdef HAVE_STRNCASECMP
716 return strncasecmp (s1
, s2
, n
);
719 for (; *s1
!= '\0' && *s2
!= '\0'; s1
++, s2
++)
724 /* According to A. Cox, some platforms have islower's that
725 * don't work right on non-uppercase
727 c1
= isupper ((guchar
) * s1
) ? tolower ((guchar
) * s1
) : *s1
;
728 c2
= isupper ((guchar
) * s2
) ? tolower ((guchar
) * s2
) : *s2
;
736 return (((gint
) (guchar
) * s1
) - ((gint
) (guchar
) * s2
));
741 /* --------------------------------------------------------------------------------------------- */
744 str_8bit_prefix (const char *text
, const char *prefix
)
748 for (result
= 0; text
[result
] != '\0' && prefix
[result
] != '\0'
749 && text
[result
] == prefix
[result
]; result
++);
754 /* --------------------------------------------------------------------------------------------- */
757 str_8bit_caseprefix (const char *text
, const char *prefix
)
761 for (result
= 0; text
[result
] != '\0' && prefix
[result
] != '\0'
762 && char_toupper (text
[result
]) == char_toupper (prefix
[result
]); result
++);
767 /* --------------------------------------------------------------------------------------------- */
770 str_8bit_fix_string (char *text
)
775 /* --------------------------------------------------------------------------------------------- */
778 str_8bit_create_key (const char *text
, gboolean case_sen
)
780 return case_sen
? (char *) text
: str_8bit_strdown (text
);
783 /* --------------------------------------------------------------------------------------------- */
786 str_8bit_key_collate (const char *t1
, const char *t2
, gboolean case_sen
)
788 return case_sen
? strcmp (t1
, t2
) : strcoll (t1
, t2
);
791 /* --------------------------------------------------------------------------------------------- */
794 str_8bit_release_key (char *key
, gboolean case_sen
)
800 /* --------------------------------------------------------------------------------------------- */
801 /*** public functions ****************************************************************************/
802 /* --------------------------------------------------------------------------------------------- */
807 struct str_class result
;
809 result
.conv_gerror_message
= str_8bit_conv_gerror_message
;
810 result
.vfs_convert_to
= str_8bit_vfs_convert_to
;
811 result
.insert_replace_char
= str_8bit_insert_replace_char
;
812 result
.is_valid_string
= str_8bit_is_valid_string
;
813 result
.is_valid_char
= str_8bit_is_valid_char
;
814 result
.cnext_char
= str_8bit_cnext_char
;
815 result
.cprev_char
= str_8bit_cprev_char
;
816 result
.cnext_char_safe
= str_8bit_cnext_char
;
817 result
.cprev_char_safe
= str_8bit_cprev_char
;
818 result
.cnext_noncomb_char
= str_8bit_cnext_noncomb_char
;
819 result
.cprev_noncomb_char
= str_8bit_cprev_noncomb_char
;
820 result
.char_isspace
= str_8bit_isspace
;
821 result
.char_ispunct
= str_8bit_ispunct
;
822 result
.char_isalnum
= str_8bit_isalnum
;
823 result
.char_isdigit
= str_8bit_isdigit
;
824 result
.char_isprint
= str_8bit_isprint
;
825 result
.char_iscombiningmark
= str_8bit_iscombiningmark
;
826 result
.char_toupper
= str_8bit_toupper
;
827 result
.char_tolower
= str_8bit_tolower
;
828 result
.length
= str_8bit_length
;
829 result
.length2
= str_8bit_length2
;
830 result
.length_noncomb
= str_8bit_length
;
831 result
.fix_string
= str_8bit_fix_string
;
832 result
.term_form
= str_8bit_term_form
;
833 result
.fit_to_term
= str_8bit_fit_to_term
;
834 result
.term_trim
= str_8bit_term_trim
;
835 result
.term_width2
= str_8bit_term_width2
;
836 result
.term_width1
= str_8bit_term_width1
;
837 result
.term_char_width
= str_8bit_term_char_width
;
838 result
.term_substring
= str_8bit_term_substring
;
839 result
.trunc
= str_8bit_trunc
;
840 result
.offset_to_pos
= str_8bit_offset_to_pos
;
841 result
.column_to_pos
= str_8bit_column_to_pos
;
842 result
.create_search_needle
= str_8bit_create_search_needle
;
843 result
.release_search_needle
= str_8bit_release_search_needle
;
844 result
.search_first
= str_8bit_search_first
;
845 result
.search_last
= str_8bit_search_last
;
846 result
.compare
= str_8bit_compare
;
847 result
.ncompare
= str_8bit_ncompare
;
848 result
.casecmp
= str_8bit_casecmp
;
849 result
.ncasecmp
= str_8bit_ncasecmp
;
850 result
.prefix
= str_8bit_prefix
;
851 result
.caseprefix
= str_8bit_caseprefix
;
852 result
.create_key
= str_8bit_create_key
;
853 result
.create_key_for_filename
= str_8bit_create_key
;
854 result
.key_collate
= str_8bit_key_collate
;
855 result
.release_key
= str_8bit_release_key
;
860 /* --------------------------------------------------------------------------------------------- */