fixed relative symlink operations. Symlink now stay relative
[midnight-commander.git] / lib / strutil / strutil8bit.c
blob92082ef31d375b20c394a032966acf17a2a5a71c
1 /* 8bit strings utilities
2 Copyright (C) 2007 Free Software Foundation, Inc.
4 Written 2007 by:
5 Rostislav Benes
7 The file_date routine is mostly from GNU's fileutils package,
8 written by Richard Stallman and David MacKenzie.
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include <config.h>
26 #include <stdio.h>
27 #include <ctype.h>
28 #include <errno.h>
30 #include "lib/global.h"
31 #include "lib/strutil.h"
33 /* functions for singlebyte encodings, all characters have width 1
34 * using standard system functions
35 * there are only small differences between functions in strutil8bit.c
36 * and strutilascii.c
39 static const char replch = '?';
42 * Inlines to equalize 'char' signedness for single 'char' encodings.
43 * Instead of writing
44 * isspace((unsigned char)c);
45 * you can write
46 * char_isspace(c);
49 #define DECLARE_CTYPE_WRAPPER(func_name) \
50 static inline int char_##func_name(char c) \
51 { \
52 return func_name((int)(unsigned char)c); \
55 /* *INDENT-OFF* */
56 DECLARE_CTYPE_WRAPPER (isalnum)
57 DECLARE_CTYPE_WRAPPER (isalpha)
58 DECLARE_CTYPE_WRAPPER (isascii)
59 DECLARE_CTYPE_WRAPPER (isblank)
60 DECLARE_CTYPE_WRAPPER (iscntrl)
61 DECLARE_CTYPE_WRAPPER (isdigit)
62 DECLARE_CTYPE_WRAPPER (isgraph)
63 DECLARE_CTYPE_WRAPPER (islower)
64 DECLARE_CTYPE_WRAPPER (isprint)
65 DECLARE_CTYPE_WRAPPER (ispunct)
66 DECLARE_CTYPE_WRAPPER (isspace)
67 DECLARE_CTYPE_WRAPPER (isupper)
68 DECLARE_CTYPE_WRAPPER (isxdigit)
69 DECLARE_CTYPE_WRAPPER (toupper)
70 DECLARE_CTYPE_WRAPPER (tolower)
71 /* *INDENT-ON* */
73 static void
74 str_8bit_insert_replace_char (GString * buffer)
76 g_string_append_c (buffer, replch);
79 static int
80 str_8bit_is_valid_string (const char *text)
82 (void) text;
83 return 1;
86 static int
87 str_8bit_is_valid_char (const char *ch, size_t size)
89 (void) ch;
90 (void) size;
91 return 1;
94 static void
95 str_8bit_cnext_char (const char **text)
97 (*text)++;
100 static void
101 str_8bit_cprev_char (const char **text)
103 (*text)--;
106 static int
107 str_8bit_cnext_noncomb_char (const char **text)
109 if (*text[0] != '\0')
111 (*text)++;
112 return 1;
114 else
115 return 0;
118 static int
119 str_8bit_cprev_noncomb_char (const char **text, const char *begin)
121 if ((*text) != begin)
123 (*text)--;
124 return 1;
126 else
127 return 0;
130 static int
131 str_8bit_isspace (const char *text)
133 return char_isspace (text[0]);
136 static int
137 str_8bit_ispunct (const char *text)
139 return char_ispunct (text[0]);
142 static int
143 str_8bit_isalnum (const char *text)
145 return char_isalnum (text[0]);
148 static int
149 str_8bit_isdigit (const char *text)
151 return char_isdigit (text[0]);
154 static int
155 str_8bit_isprint (const char *text)
157 return char_isprint (text[0]);
160 static int
161 str_8bit_iscombiningmark (const char *text)
163 (void) text;
164 return 0;
167 static int
168 str_8bit_toupper (const char *text, char **out, size_t * remain)
170 if (*remain <= 1)
171 return 0;
172 (*out)[0] = char_toupper (text[0]);
173 (*out)++;
174 (*remain)--;
175 return 1;
178 static int
179 str_8bit_tolower (const char *text, char **out, size_t * remain)
181 if (*remain <= 1)
182 return 0;
183 (*out)[0] = char_tolower (text[0]);
184 (*out)++;
185 (*remain)--;
186 return 1;
189 static int
190 str_8bit_length (const char *text)
192 return strlen (text);
195 static int
196 str_8bit_length2 (const char *text, int size)
198 return (size >= 0) ? min (strlen (text), (gsize) size) : strlen (text);
201 static gchar *
202 str_8bit_conv_gerror_message (GError * error, const char *def_msg)
204 GIConv conv;
205 gchar *ret;
207 /* glib messages are in UTF-8 charset */
208 conv = str_crt_conv_from ("UTF-8");
210 if (conv == INVALID_CONV)
211 ret = g_strdup (def_msg != NULL ? def_msg : "");
212 else
214 GString *buf;
216 buf = g_string_new ("");
218 if (str_convert (conv, error->message, buf) != ESTR_FAILURE)
220 ret = buf->str;
221 g_string_free (buf, FALSE);
223 else
225 ret = g_strdup (def_msg != NULL ? def_msg : "");
226 g_string_free (buf, TRUE);
229 str_close_conv (conv);
232 return ret;
235 static estr_t
236 str_8bit_vfs_convert_to (GIConv coder, const char *string, int size, GString * buffer)
238 estr_t result;
240 if (coder == str_cnv_not_convert)
242 g_string_append_len (buffer, string, size);
243 result = ESTR_SUCCESS;
245 else
246 result = str_nconvert (coder, (char *) string, size, buffer);
248 return result;
252 static const char *
253 str_8bit_term_form (const char *text)
255 static char result[BUF_MEDIUM];
256 char *actual;
257 size_t remain;
258 size_t length;
259 size_t pos = 0;
261 actual = result;
262 remain = sizeof (result);
263 length = strlen (text);
265 for (; pos < length && remain > 1; pos++, actual++, remain--)
267 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
270 actual[0] = '\0';
271 return result;
274 static const char *
275 str_8bit_fit_to_term (const char *text, int width, align_crt_t just_mode)
277 static char result[BUF_MEDIUM];
278 char *actual;
279 size_t remain;
280 int ident;
281 size_t length;
282 size_t pos = 0;
284 length = strlen (text);
285 actual = result;
286 remain = sizeof (result);
288 if ((int) length <= width)
290 ident = 0;
291 switch (HIDE_FIT (just_mode))
293 case J_CENTER_LEFT:
294 case J_CENTER:
295 ident = (width - length) / 2;
296 break;
297 case J_RIGHT:
298 ident = width - length;
299 break;
302 if ((int) remain <= ident)
303 goto finally;
304 memset (actual, ' ', ident);
305 actual += ident;
306 remain -= ident;
308 for (; pos < length && remain > 1; pos++, actual++, remain--)
310 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
312 if (width - length - ident > 0)
314 if (remain <= width - length - ident)
315 goto finally;
316 memset (actual, ' ', width - length - ident);
317 actual += width - length - ident;
318 remain -= 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 < (int) length)
386 if (width <= 3)
388 memset (actual, '.', width);
389 actual += width;
390 remain -= width;
392 else
394 memset (actual, '.', 3);
395 actual += 3;
396 remain -= 3;
398 pos += length - width + 3;
400 for (; pos < length && remain > 1; pos++, actual++, remain--)
402 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
406 else
408 for (; pos < length && remain > 1; pos++, actual++, remain--)
410 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
414 actual[0] = '\0';
415 return result;
418 static int
419 str_8bit_term_width2 (const char *text, size_t length)
421 return (length != (size_t) (-1)) ? min (strlen (text), length) : strlen (text);
424 static int
425 str_8bit_term_width1 (const char *text)
427 return str_8bit_term_width2 (text, (size_t) (-1));
430 static int
431 str_8bit_term_char_width (const char *text)
433 (void) text;
434 return 1;
437 static const char *
438 str_8bit_term_substring (const char *text, int start, int width)
440 static char result[BUF_MEDIUM];
441 size_t remain;
442 char *actual;
443 size_t pos = 0;
444 size_t length;
446 actual = result;
447 remain = sizeof (result);
448 length = strlen (text);
450 if (start < (int) length)
452 pos += start;
453 for (; pos < length && width > 0 && remain > 1; pos++, width--, actual++, remain--)
456 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
460 for (; width > 0 && remain > 1; actual++, remain--, width--)
462 actual[0] = ' ';
465 actual[0] = '\0';
466 return result;
469 static const char *
470 str_8bit_trunc (const char *text, int width)
472 static char result[MC_MAXPATHLEN];
473 int remain;
474 char *actual;
475 size_t pos = 0;
476 size_t length;
478 actual = result;
479 remain = sizeof (result);
480 length = strlen (text);
482 if ((int) length > width)
484 for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--)
486 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
489 if (remain <= 1)
490 goto finally;
491 actual[0] = '~';
492 actual++;
493 remain--;
495 pos += length - width + 1;
497 for (; pos < length && remain > 1; pos++, actual++, remain--)
499 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
502 else
504 for (; pos < length && remain > 1; pos++, actual++, remain--)
506 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
510 finally:
511 actual[0] = '\0';
512 return result;
515 static int
516 str_8bit_offset_to_pos (const char *text, size_t length)
518 (void) text;
519 return (int) length;
522 static int
523 str_8bit_column_to_pos (const char *text, size_t pos)
525 (void) text;
526 return (int) pos;
529 static char *
530 str_8bit_create_search_needle (const char *needle, int case_sen)
532 (void) case_sen;
533 return (char *) needle;
536 static void
537 str_8bit_release_search_needle (char *needle, int case_sen)
539 (void) case_sen;
540 (void) needle;
543 static char *
544 str_8bit_strdown (const char *str)
546 char *rets, *p;
548 rets = g_strdup (str);
549 if (rets == NULL)
550 return NULL;
552 for (p = rets; *p != '\0'; p++)
553 *p = char_tolower (*p);
555 return rets;
559 static const char *
560 str_8bit_search_first (const char *text, const char *search, int case_sen)
562 char *fold_text;
563 char *fold_search;
564 const char *match;
565 size_t offsset;
567 fold_text = (case_sen) ? (char *) text : str_8bit_strdown (text);
568 fold_search = (case_sen) ? (char *) search : str_8bit_strdown (search);
570 match = g_strstr_len (fold_text, -1, fold_search);
571 if (match != NULL)
573 offsset = match - fold_text;
574 match = text + offsset;
577 if (!case_sen)
579 g_free (fold_text);
580 g_free (fold_search);
583 return match;
586 static const char *
587 str_8bit_search_last (const char *text, const char *search, int case_sen)
589 char *fold_text;
590 char *fold_search;
591 const char *match;
592 size_t offsset;
594 fold_text = (case_sen) ? (char *) text : str_8bit_strdown (text);
595 fold_search = (case_sen) ? (char *) search : str_8bit_strdown (search);
597 match = g_strrstr_len (fold_text, -1, fold_search);
598 if (match != NULL)
600 offsset = match - fold_text;
601 match = text + offsset;
604 if (!case_sen)
606 g_free (fold_text);
607 g_free (fold_search);
610 return match;
613 static int
614 str_8bit_compare (const char *t1, const char *t2)
616 return strcmp (t1, t2);
619 static int
620 str_8bit_ncompare (const char *t1, const char *t2)
622 return strncmp (t1, t2, min (strlen (t1), strlen (t2)));
625 static int
626 str_8bit_casecmp (const char *s1, const char *s2)
628 /* code from GLib */
630 #ifdef HAVE_STRCASECMP
631 g_return_val_if_fail (s1 != NULL, 0);
632 g_return_val_if_fail (s2 != NULL, 0);
634 return strcasecmp (s1, s2);
635 #else
636 gint c1, c2;
638 g_return_val_if_fail (s1 != NULL, 0);
639 g_return_val_if_fail (s2 != NULL, 0);
641 while (*s1 != '\0' && *s2 != '\0')
643 /* According to A. Cox, some platforms have islower's that
644 * don't work right on non-uppercase
646 c1 = isupper ((guchar) * s1) ? tolower ((guchar) * s1) : *s1;
647 c2 = isupper ((guchar) * s2) ? tolower ((guchar) * s2) : *s2;
648 if (c1 != c2)
649 return (c1 - c2);
650 s1++;
651 s2++;
654 return (((gint) (guchar) * s1) - ((gint) (guchar) * s2));
655 #endif
658 static int
659 str_8bit_ncasecmp (const char *s1, const char *s2)
661 size_t n;
663 g_return_val_if_fail (s1 != NULL, 0);
664 g_return_val_if_fail (s2 != NULL, 0);
666 n = min (strlen (s1), strlen (s2));
668 /* code from GLib */
670 #ifdef HAVE_STRNCASECMP
671 return strncasecmp (s1, s2, n);
672 #else
673 gint c1, c2;
675 while (n != 0 && *s1 != '\0' && *s2 != '\0')
677 n -= 1;
678 /* According to A. Cox, some platforms have islower's that
679 * don't work right on non-uppercase
681 c1 = isupper ((guchar) * s1) ? tolower ((guchar) * s1) : *s1;
682 c2 = isupper ((guchar) * s2) ? tolower ((guchar) * s2) : *s2;
683 if (c1 != c2)
684 return (c1 - c2);
685 s1++;
686 s2++;
689 if (n != 0)
690 return (((gint) (guchar) * s1) - ((gint) (guchar) * s2));
691 else
692 return 0;
693 #endif
696 static int
697 str_8bit_prefix (const char *text, const char *prefix)
699 int result;
700 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
701 && text[result] == prefix[result]; result++);
702 return result;
705 static int
706 str_8bit_caseprefix (const char *text, const char *prefix)
708 int result;
709 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
710 && char_toupper (text[result]) == char_toupper (prefix[result]); result++);
711 return result;
716 static void
717 str_8bit_fix_string (char *text)
719 (void) text;
722 static char *
723 str_8bit_create_key (const char *text, int case_sen)
725 return (case_sen) ? (char *) text : str_8bit_strdown (text);
728 static int
729 str_8bit_key_collate (const char *t1, const char *t2, int case_sen)
731 if (case_sen)
732 return strcmp (t1, t2);
733 else
734 return strcoll (t1, t2);
737 static void
738 str_8bit_release_key (char *key, int case_sen)
740 if (!case_sen)
741 g_free (key);
744 struct str_class
745 str_8bit_init (void)
747 struct str_class result;
749 result.conv_gerror_message = str_8bit_conv_gerror_message;
750 result.vfs_convert_to = str_8bit_vfs_convert_to;
751 result.insert_replace_char = str_8bit_insert_replace_char;
752 result.is_valid_string = str_8bit_is_valid_string;
753 result.is_valid_char = str_8bit_is_valid_char;
754 result.cnext_char = str_8bit_cnext_char;
755 result.cprev_char = str_8bit_cprev_char;
756 result.cnext_char_safe = str_8bit_cnext_char;
757 result.cprev_char_safe = str_8bit_cprev_char;
758 result.cnext_noncomb_char = str_8bit_cnext_noncomb_char;
759 result.cprev_noncomb_char = str_8bit_cprev_noncomb_char;
760 result.isspace = str_8bit_isspace;
761 result.ispunct = str_8bit_ispunct;
762 result.isalnum = str_8bit_isalnum;
763 result.isdigit = str_8bit_isdigit;
764 result.isprint = str_8bit_isprint;
765 result.iscombiningmark = str_8bit_iscombiningmark;
766 result.toupper = str_8bit_toupper;
767 result.tolower = str_8bit_tolower;
768 result.length = str_8bit_length;
769 result.length2 = str_8bit_length2;
770 result.length_noncomb = str_8bit_length;
771 result.fix_string = str_8bit_fix_string;
772 result.term_form = str_8bit_term_form;
773 result.fit_to_term = str_8bit_fit_to_term;
774 result.term_trim = str_8bit_term_trim;
775 result.term_width2 = str_8bit_term_width2;
776 result.term_width1 = str_8bit_term_width1;
777 result.term_char_width = str_8bit_term_char_width;
778 result.term_substring = str_8bit_term_substring;
779 result.trunc = str_8bit_trunc;
780 result.offset_to_pos = str_8bit_offset_to_pos;
781 result.column_to_pos = str_8bit_column_to_pos;
782 result.create_search_needle = str_8bit_create_search_needle;
783 result.release_search_needle = str_8bit_release_search_needle;
784 result.search_first = str_8bit_search_first;
785 result.search_last = str_8bit_search_last;
786 result.compare = str_8bit_compare;
787 result.ncompare = str_8bit_ncompare;
788 result.casecmp = str_8bit_casecmp;
789 result.ncasecmp = str_8bit_ncasecmp;
790 result.prefix = str_8bit_prefix;
791 result.caseprefix = str_8bit_caseprefix;
792 result.create_key = str_8bit_create_key;
793 result.create_key_for_filename = str_8bit_create_key;
794 result.key_collate = str_8bit_key_collate;
795 result.release_key = str_8bit_release_key;
797 return result;