Updated doc/NEWS file
[midnight-commander.git] / lib / strutil / strutil8bit.c
blob53a78cad8bc3b5ccce258c56baa0e3012fba48a2
1 /*
2 8bit strings utilities
4 Copyright (C) 2007, 2011
5 The Free Software Foundation, Inc.
7 Written by:
8 Rostislav Benes, 2007
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/>.
26 #include <config.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <errno.h>
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
37 * and strutilascii.c
40 static const char replch = '?';
43 * Inlines to equalize 'char' signedness for single 'char' encodings.
44 * Instead of writing
45 * isspace((unsigned char)c);
46 * you can write
47 * char_isspace(c);
50 #define DECLARE_CTYPE_WRAPPER(func_name) \
51 static inline int char_##func_name(char c) \
52 { \
53 return func_name((int)(unsigned char)c); \
56 /* *INDENT-OFF* */
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)
72 /* *INDENT-ON* */
74 static void
75 str_8bit_insert_replace_char (GString * buffer)
77 g_string_append_c (buffer, replch);
80 static int
81 str_8bit_is_valid_string (const char *text)
83 (void) text;
84 return 1;
87 static int
88 str_8bit_is_valid_char (const char *ch, size_t size)
90 (void) ch;
91 (void) size;
92 return 1;
95 static void
96 str_8bit_cnext_char (const char **text)
98 (*text)++;
101 static void
102 str_8bit_cprev_char (const char **text)
104 (*text)--;
107 static int
108 str_8bit_cnext_noncomb_char (const char **text)
110 if (*text[0] != '\0')
112 (*text)++;
113 return 1;
115 else
116 return 0;
119 static int
120 str_8bit_cprev_noncomb_char (const char **text, const char *begin)
122 if ((*text) != begin)
124 (*text)--;
125 return 1;
127 else
128 return 0;
131 static int
132 str_8bit_isspace (const char *text)
134 return char_isspace (text[0]);
137 static int
138 str_8bit_ispunct (const char *text)
140 return char_ispunct (text[0]);
143 static int
144 str_8bit_isalnum (const char *text)
146 return char_isalnum (text[0]);
149 static int
150 str_8bit_isdigit (const char *text)
152 return char_isdigit (text[0]);
155 static int
156 str_8bit_isprint (const char *text)
158 return char_isprint (text[0]);
161 static gboolean
162 str_8bit_iscombiningmark (const char *text)
164 (void) text;
165 return FALSE;
168 static int
169 str_8bit_toupper (const char *text, char **out, size_t * remain)
171 if (*remain <= 1)
172 return 0;
173 (*out)[0] = char_toupper (text[0]);
174 (*out)++;
175 (*remain)--;
176 return 1;
179 static int
180 str_8bit_tolower (const char *text, char **out, size_t * remain)
182 if (*remain <= 1)
183 return 0;
184 (*out)[0] = char_tolower (text[0]);
185 (*out)++;
186 (*remain)--;
187 return 1;
190 static int
191 str_8bit_length (const char *text)
193 return strlen (text);
196 static int
197 str_8bit_length2 (const char *text, int size)
199 return (size >= 0) ? min (strlen (text), (gsize) size) : strlen (text);
202 static gchar *
203 str_8bit_conv_gerror_message (GError * error, const char *def_msg)
205 GIConv conv;
206 gchar *ret;
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 : "");
213 else
215 GString *buf;
217 buf = g_string_new ("");
219 if (str_convert (conv, error->message, buf) != ESTR_FAILURE)
221 ret = buf->str;
222 g_string_free (buf, FALSE);
224 else
226 ret = g_strdup (def_msg != NULL ? def_msg : "");
227 g_string_free (buf, TRUE);
230 str_close_conv (conv);
233 return ret;
236 static estr_t
237 str_8bit_vfs_convert_to (GIConv coder, const char *string, int size, GString * buffer)
239 estr_t result;
241 if (coder == str_cnv_not_convert)
243 g_string_append_len (buffer, string, size);
244 result = ESTR_SUCCESS;
246 else
247 result = str_nconvert (coder, (char *) string, size, buffer);
249 return result;
253 static const char *
254 str_8bit_term_form (const char *text)
256 static char result[BUF_MEDIUM];
257 char *actual;
258 size_t remain;
259 size_t length;
260 size_t pos = 0;
262 actual = result;
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] : '.';
271 actual[0] = '\0';
272 return result;
275 static const char *
276 str_8bit_fit_to_term (const char *text, int width, align_crt_t just_mode)
278 static char result[BUF_MEDIUM];
279 char *actual;
280 size_t remain;
281 int ident;
282 size_t length;
283 size_t pos = 0;
285 length = strlen (text);
286 actual = result;
287 remain = sizeof (result);
289 if ((int) length <= width)
291 ident = 0;
292 switch (HIDE_FIT (just_mode))
294 case J_CENTER_LEFT:
295 case J_CENTER:
296 ident = (width - length) / 2;
297 break;
298 case J_RIGHT:
299 ident = width - length;
300 break;
303 if ((int) remain <= ident)
304 goto finally;
305 memset (actual, ' ', ident);
306 actual += ident;
307 remain -= 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)
316 goto finally;
317 memset (actual, ' ', width - length - ident);
318 actual += width - length - ident;
321 else
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] : '.';
331 if (remain <= 1)
332 goto finally;
333 actual[0] = '~';
334 actual++;
335 remain--;
337 pos += length - width + 1;
339 for (; pos < length && remain > 1; pos++, actual++, remain--)
341 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
344 else
346 ident = 0;
347 switch (HIDE_FIT (just_mode))
349 case J_CENTER:
350 ident = (length - width) / 2;
351 break;
352 case J_RIGHT:
353 ident = length - width;
354 break;
357 pos += ident;
358 for (; pos < (gsize) (ident + width) && remain > 1; pos++, actual++, remain--)
361 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
366 finally:
367 actual[0] = '\0';
368 return result;
371 static const char *
372 str_8bit_term_trim (const char *text, int width)
374 static char result[BUF_MEDIUM];
375 size_t remain;
376 char *actual;
377 size_t pos = 0;
378 size_t length;
380 length = strlen (text);
381 actual = result;
382 remain = sizeof (result);
384 if (width > 0)
386 if (width < (int) length)
388 if (width <= 3)
390 memset (actual, '.', width);
391 actual += width;
393 else
395 memset (actual, '.', 3);
396 actual += 3;
397 remain -= 3;
399 pos += length - width + 3;
401 for (; pos < length && remain > 1; pos++, actual++, remain--)
402 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
405 else
407 for (; pos < length && remain > 1; pos++, actual++, remain--)
408 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
412 actual[0] = '\0';
413 return result;
416 static int
417 str_8bit_term_width2 (const char *text, size_t length)
419 return (length != (size_t) (-1)) ? min (strlen (text), length) : strlen (text);
422 static int
423 str_8bit_term_width1 (const char *text)
425 return str_8bit_term_width2 (text, (size_t) (-1));
428 static int
429 str_8bit_term_char_width (const char *text)
431 (void) text;
432 return 1;
435 static const char *
436 str_8bit_term_substring (const char *text, int start, int width)
438 static char result[BUF_MEDIUM];
439 size_t remain;
440 char *actual;
441 size_t pos = 0;
442 size_t length;
444 actual = result;
445 remain = sizeof (result);
446 length = strlen (text);
448 if (start < (int) length)
450 pos += start;
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--)
460 actual[0] = ' ';
463 actual[0] = '\0';
464 return result;
467 static const char *
468 str_8bit_trunc (const char *text, int width)
470 static char result[MC_MAXPATHLEN];
471 int remain;
472 char *actual;
473 size_t pos = 0;
474 size_t length;
476 actual = result;
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] : '.';
487 if (remain <= 1)
488 goto finally;
489 actual[0] = '~';
490 actual++;
491 remain--;
493 pos += length - width + 1;
495 for (; pos < length && remain > 1; pos++, actual++, remain--)
497 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
500 else
502 for (; pos < length && remain > 1; pos++, actual++, remain--)
504 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
508 finally:
509 actual[0] = '\0';
510 return result;
513 static int
514 str_8bit_offset_to_pos (const char *text, size_t length)
516 (void) text;
517 return (int) length;
520 static int
521 str_8bit_column_to_pos (const char *text, size_t pos)
523 (void) text;
524 return (int) pos;
527 static char *
528 str_8bit_create_search_needle (const char *needle, int case_sen)
530 (void) case_sen;
531 return (char *) needle;
534 static void
535 str_8bit_release_search_needle (char *needle, int case_sen)
537 (void) case_sen;
538 (void) needle;
541 static char *
542 str_8bit_strdown (const char *str)
544 char *rets, *p;
546 rets = g_strdup (str);
547 if (rets == NULL)
548 return NULL;
550 for (p = rets; *p != '\0'; p++)
551 *p = char_tolower (*p);
553 return rets;
557 static const char *
558 str_8bit_search_first (const char *text, const char *search, int case_sen)
560 char *fold_text;
561 char *fold_search;
562 const char *match;
563 size_t offsset;
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);
569 if (match != NULL)
571 offsset = match - fold_text;
572 match = text + offsset;
575 if (!case_sen)
577 g_free (fold_text);
578 g_free (fold_search);
581 return match;
584 static const char *
585 str_8bit_search_last (const char *text, const char *search, int case_sen)
587 char *fold_text;
588 char *fold_search;
589 const char *match;
590 size_t offsset;
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);
596 if (match != NULL)
598 offsset = match - fold_text;
599 match = text + offsset;
602 if (!case_sen)
604 g_free (fold_text);
605 g_free (fold_search);
608 return match;
611 static int
612 str_8bit_compare (const char *t1, const char *t2)
614 return strcmp (t1, t2);
617 static int
618 str_8bit_ncompare (const char *t1, const char *t2)
620 return strncmp (t1, t2, min (strlen (t1), strlen (t2)));
623 static int
624 str_8bit_casecmp (const char *s1, const char *s2)
626 /* code from GLib */
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);
633 #else
634 gint c1, c2;
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;
646 if (c1 != c2)
647 return (c1 - c2);
648 s1++;
649 s2++;
652 return (((gint) (guchar) * s1) - ((gint) (guchar) * s2));
653 #endif
656 static int
657 str_8bit_ncasecmp (const char *s1, const char *s2)
659 size_t n;
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));
666 /* code from GLib */
668 #ifdef HAVE_STRNCASECMP
669 return strncasecmp (s1, s2, n);
670 #else
671 gint c1, c2;
673 while (n != 0 && *s1 != '\0' && *s2 != '\0')
675 n -= 1;
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;
681 if (c1 != c2)
682 return (c1 - c2);
683 s1++;
684 s2++;
687 if (n != 0)
688 return (((gint) (guchar) * s1) - ((gint) (guchar) * s2));
689 else
690 return 0;
691 #endif
694 static int
695 str_8bit_prefix (const char *text, const char *prefix)
697 int result;
698 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
699 && text[result] == prefix[result]; result++);
700 return result;
703 static int
704 str_8bit_caseprefix (const char *text, const char *prefix)
706 int result;
707 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
708 && char_toupper (text[result]) == char_toupper (prefix[result]); result++);
709 return result;
714 static void
715 str_8bit_fix_string (char *text)
717 (void) text;
720 static char *
721 str_8bit_create_key (const char *text, int case_sen)
723 return (case_sen) ? (char *) text : str_8bit_strdown (text);
726 static int
727 str_8bit_key_collate (const char *t1, const char *t2, int case_sen)
729 if (case_sen)
730 return strcmp (t1, t2);
731 else
732 return strcoll (t1, t2);
735 static void
736 str_8bit_release_key (char *key, int case_sen)
738 if (!case_sen)
739 g_free (key);
742 struct str_class
743 str_8bit_init (void)
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;
795 return result;