Fixed fileOperation dialog height for copy/move operations (with verbose mode switche...
[midnight-commander.git] / lib / strutil / strutil8bit.c
blobf8a934fc0c9ac18d484bb911c92b5aa3bd33b980
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 DECLARE_CTYPE_WRAPPER(isalnum)
56 DECLARE_CTYPE_WRAPPER(isalpha)
57 DECLARE_CTYPE_WRAPPER(isascii)
58 DECLARE_CTYPE_WRAPPER(isblank)
59 DECLARE_CTYPE_WRAPPER(iscntrl)
60 DECLARE_CTYPE_WRAPPER(isdigit)
61 DECLARE_CTYPE_WRAPPER(isgraph)
62 DECLARE_CTYPE_WRAPPER(islower)
63 DECLARE_CTYPE_WRAPPER(isprint)
64 DECLARE_CTYPE_WRAPPER(ispunct)
65 DECLARE_CTYPE_WRAPPER(isspace)
66 DECLARE_CTYPE_WRAPPER(isupper)
67 DECLARE_CTYPE_WRAPPER(isxdigit)
68 DECLARE_CTYPE_WRAPPER(toupper)
69 DECLARE_CTYPE_WRAPPER(tolower)
71 static void
72 str_8bit_insert_replace_char (GString * buffer)
74 g_string_append_c (buffer, replch);
77 static int
78 str_8bit_is_valid_string (const char *text)
80 (void) text;
81 return 1;
84 static int
85 str_8bit_is_valid_char (const char *ch, size_t size)
87 (void) ch;
88 (void) size;
89 return 1;
92 static void
93 str_8bit_cnext_char (const char **text)
95 (*text)++;
98 static void
99 str_8bit_cprev_char (const char **text)
101 (*text)--;
104 static int
105 str_8bit_cnext_noncomb_char (const char **text)
107 if (*text[0] != '\0')
109 (*text)++;
110 return 1;
112 else
113 return 0;
116 static int
117 str_8bit_cprev_noncomb_char (const char **text, const char *begin)
119 if ((*text) != begin)
121 (*text)--;
122 return 1;
124 else
125 return 0;
128 static int
129 str_8bit_isspace (const char *text)
131 return char_isspace (text[0]);
134 static int
135 str_8bit_ispunct (const char *text)
137 return char_ispunct (text[0]);
140 static int
141 str_8bit_isalnum (const char *text)
143 return char_isalnum (text[0]);
146 static int
147 str_8bit_isdigit (const char *text)
149 return char_isdigit (text[0]);
152 static int
153 str_8bit_isprint (const char *text)
155 return char_isprint (text[0]);
158 static int
159 str_8bit_iscombiningmark (const char *text)
161 (void) text;
162 return 0;
165 static int
166 str_8bit_toupper (const char *text, char **out, size_t * remain)
168 if (*remain <= 1)
169 return 0;
170 (*out)[0] = char_toupper (text[0]);
171 (*out)++;
172 (*remain)--;
173 return 1;
176 static int
177 str_8bit_tolower (const char *text, char **out, size_t * remain)
179 if (*remain <= 1)
180 return 0;
181 (*out)[0] = char_tolower (text[0]);
182 (*out)++;
183 (*remain)--;
184 return 1;
187 static int
188 str_8bit_length (const char *text)
190 return strlen (text);
193 static int
194 str_8bit_length2 (const char *text, int size)
196 return (size >= 0) ? min (strlen (text), (gsize)size) : strlen (text);
199 static gchar *
200 str_8bit_conv_gerror_message (GError *error, const char *def_msg)
202 GIConv conv;
203 gchar *ret;
205 /* glib messages are in UTF-8 charset */
206 conv = str_crt_conv_from ("UTF-8");
208 if (conv == INVALID_CONV)
209 ret = g_strdup (def_msg != NULL ? def_msg : "");
210 else {
211 GString *buf;
213 buf = g_string_new ("");
215 if (str_convert (conv, error->message, buf) != ESTR_FAILURE) {
216 ret = buf->str;
217 g_string_free (buf, FALSE);
218 } else {
219 ret = g_strdup (def_msg != NULL ? def_msg : "");
220 g_string_free (buf, TRUE);
223 str_close_conv (conv);
226 return ret;
229 static estr_t
230 str_8bit_vfs_convert_to (GIConv coder, const char *string,
231 int size, GString * buffer)
233 estr_t result;
235 if (coder == str_cnv_not_convert)
237 g_string_append_len (buffer, string, size);
238 result = ESTR_SUCCESS;
240 else
241 result = str_nconvert (coder, (char *) string, size, buffer);
243 return result;
247 static const char *
248 str_8bit_term_form (const char *text)
250 static char result[BUF_MEDIUM];
251 char *actual;
252 size_t remain;
253 size_t length;
254 size_t pos = 0;
256 actual = result;
257 remain = sizeof (result);
258 length = strlen (text);
260 for (; pos < length && remain > 1; pos++, actual++, remain--)
262 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
265 actual[0] = '\0';
266 return result;
269 static const char *
270 str_8bit_fit_to_term (const char *text, int width, align_crt_t just_mode)
272 static char result[BUF_MEDIUM];
273 char *actual;
274 size_t remain;
275 int ident;
276 size_t length;
277 size_t pos = 0;
279 length = strlen (text);
280 actual = result;
281 remain = sizeof (result);
283 if ((int)length <= width)
285 ident = 0;
286 switch (HIDE_FIT (just_mode))
288 case J_CENTER_LEFT:
289 case J_CENTER:
290 ident = (width - length) / 2;
291 break;
292 case J_RIGHT:
293 ident = width - length;
294 break;
297 if ((int)remain <= ident)
298 goto finally;
299 memset (actual, ' ', ident);
300 actual += ident;
301 remain -= ident;
303 for (; pos < length && remain > 1; pos++, actual++, remain--)
305 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
307 if (width - length - ident > 0)
309 if (remain <= width - length - ident)
310 goto finally;
311 memset (actual, ' ', width - length - ident);
312 actual += width - length - ident;
313 remain -= width - length - ident;
316 else
318 if (IS_FIT (just_mode))
320 for (; pos + 1 <= (gsize)width / 2 && remain > 1;
321 actual++, pos++, remain--)
324 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
327 if (remain <= 1)
328 goto finally;
329 actual[0] = '~';
330 actual++;
331 remain--;
333 pos += length - width + 1;
335 for (; pos < length && remain > 1; pos++, actual++, remain--)
337 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
340 else
342 ident = 0;
343 switch (HIDE_FIT (just_mode))
345 case J_CENTER:
346 ident = (length - width) / 2;
347 break;
348 case J_RIGHT:
349 ident = length - width;
350 break;
353 pos += ident;
354 for (; pos < (gsize)(ident + width) && remain > 1;
355 pos++, actual++, remain--)
358 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
363 finally:
364 actual[0] = '\0';
365 return result;
368 static const char *
369 str_8bit_term_trim (const char *text, int width)
371 static char result[BUF_MEDIUM];
372 size_t remain;
373 char *actual;
374 size_t pos = 0;
375 size_t length;
377 length = strlen (text);
378 actual = result;
379 remain = sizeof (result);
381 if (width < (int)length)
383 if (width <= 3)
385 memset (actual, '.', width);
386 actual += width;
387 remain -= width;
389 else
391 memset (actual, '.', 3);
392 actual += 3;
393 remain -= 3;
395 pos += length - width + 3;
397 for (; pos < length && remain > 1; pos++, actual++, remain--)
399 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
403 else
405 for (; pos < length && remain > 1; pos++, actual++, remain--)
407 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
411 actual[0] = '\0';
412 return result;
415 static int
416 str_8bit_term_width2 (const char *text, size_t length)
418 return (length != (size_t) (-1))
419 ? 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 void
436 str_8bit_msg_term_size (const char *text, int *lines, int *columns)
439 char *p, *tmp;
440 char *q;
441 char c = '\0';
442 int width;
444 (*lines) = 1;
445 (*columns) = 0;
446 tmp = g_strdup ((char *)text);
447 p = tmp;
448 for (;;)
450 q = strchr (p, '\n');
451 if (q != NULL)
453 c = q[0];
454 q[0] = '\0';
457 width = str_8bit_term_width1 (p);
458 if (width > (*columns))
459 (*columns) = width;
461 if (q == NULL)
462 break;
463 q[0] = c;
464 p = q + 1;
465 (*lines)++;
467 g_free (tmp);
470 static const char *
471 str_8bit_term_substring (const char *text, int start, int width)
473 static char result[BUF_MEDIUM];
474 size_t remain;
475 char *actual;
476 size_t pos = 0;
477 size_t length;
479 actual = result;
480 remain = sizeof (result);
481 length = strlen (text);
483 if (start < (int)length)
485 pos += start;
486 for (; pos < length && width > 0 && remain > 1;
487 pos++, width--, actual++, remain--)
490 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
494 for (; width > 0 && remain > 1; actual++, remain--, width--)
496 actual[0] = ' ';
499 actual[0] = '\0';
500 return result;
503 static const char *
504 str_8bit_trunc (const char *text, int width)
506 static char result[MC_MAXPATHLEN];
507 int remain;
508 char *actual;
509 size_t pos = 0;
510 size_t length;
512 actual = result;
513 remain = sizeof (result);
514 length = strlen (text);
516 if ((int)length > width)
518 for (; pos + 1 <= (gsize)width / 2 && remain > 1; actual++, pos++, remain--)
520 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
523 if (remain <= 1)
524 goto finally;
525 actual[0] = '~';
526 actual++;
527 remain--;
529 pos += length - width + 1;
531 for (; pos < length && remain > 1; pos++, actual++, remain--)
533 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
536 else
538 for (; pos < length && remain > 1; pos++, actual++, remain--)
540 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
544 finally:
545 actual[0] = '\0';
546 return result;
549 static int
550 str_8bit_offset_to_pos (const char *text, size_t length)
552 (void) text;
553 return (int) length;
556 static int
557 str_8bit_column_to_pos (const char *text, size_t pos)
559 (void) text;
560 return (int)pos;
563 static char *
564 str_8bit_create_search_needle (const char *needle, int case_sen)
566 (void) case_sen;
567 return (char *) needle;
570 static void
571 str_8bit_release_search_needle (char *needle, int case_sen)
573 (void) case_sen;
574 (void) needle;
577 static const char *
578 str_8bit_search_first (const char *text, const char *search, int case_sen)
580 char *fold_text;
581 char *fold_search;
582 const char *match;
583 size_t offsset;
585 fold_text = (case_sen) ? (char *) text : g_strdown (g_strdup (text));
586 fold_search = (case_sen) ? (char *) search : g_strdown (g_strdup (search));
588 match = g_strstr_len (fold_text, -1, fold_search);
589 if (match != NULL)
591 offsset = match - fold_text;
592 match = text + offsset;
595 if (!case_sen)
597 g_free (fold_text);
598 g_free (fold_search);
601 return match;
604 static const char *
605 str_8bit_search_last (const char *text, const char *search, int case_sen)
607 char *fold_text;
608 char *fold_search;
609 const char *match;
610 size_t offsset;
612 fold_text = (case_sen) ? (char *) text : g_strdown (g_strdup (text));
613 fold_search = (case_sen) ? (char *) search : g_strdown (g_strdup (search));
615 match = g_strrstr_len (fold_text, -1, fold_search);
616 if (match != NULL)
618 offsset = match - fold_text;
619 match = text + offsset;
622 if (!case_sen)
624 g_free (fold_text);
625 g_free (fold_search);
628 return match;
631 static int
632 str_8bit_compare (const char *t1, const char *t2)
634 return strcmp (t1, t2);
637 static int
638 str_8bit_ncompare (const char *t1, const char *t2)
640 return strncmp (t1, t2, min (strlen (t1), strlen (t2)));
643 static int
644 str_8bit_casecmp (const char *t1, const char *t2)
646 return g_strcasecmp (t1, t2);
649 static int
650 str_8bit_ncasecmp (const char *t1, const char *t2)
652 return g_strncasecmp (t1, t2, min (strlen (t1), strlen (t2)));
655 static int
656 str_8bit_prefix (const char *text, const char *prefix)
658 int result;
659 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
660 && text[result] == prefix[result]; result++);
661 return result;
664 static int
665 str_8bit_caseprefix (const char *text, const char *prefix)
667 int result;
668 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
669 && char_toupper (text[result]) == char_toupper (prefix[result]); result++);
670 return result;
675 static void
676 str_8bit_fix_string (char *text)
678 (void) text;
681 static char *
682 str_8bit_create_key (const char *text, int case_sen)
684 return (case_sen) ? (char *) text : g_strdown (g_strdup (text));
687 static int
688 str_8bit_key_collate (const char *t1, const char *t2, int case_sen)
690 if (case_sen)
691 return strcmp (t1, t2);
692 else
693 return strcoll (t1, t2);
696 static void
697 str_8bit_release_key (char *key, int case_sen)
699 if (!case_sen)
700 g_free (key);
703 struct str_class
704 str_8bit_init (void)
706 struct str_class result;
708 result.conv_gerror_message = str_8bit_conv_gerror_message;
709 result.vfs_convert_to = str_8bit_vfs_convert_to;
710 result.insert_replace_char = str_8bit_insert_replace_char;
711 result.is_valid_string = str_8bit_is_valid_string;
712 result.is_valid_char = str_8bit_is_valid_char;
713 result.cnext_char = str_8bit_cnext_char;
714 result.cprev_char = str_8bit_cprev_char;
715 result.cnext_char_safe = str_8bit_cnext_char;
716 result.cprev_char_safe = str_8bit_cprev_char;
717 result.cnext_noncomb_char = str_8bit_cnext_noncomb_char;
718 result.cprev_noncomb_char = str_8bit_cprev_noncomb_char;
719 result.isspace = str_8bit_isspace;
720 result.ispunct = str_8bit_ispunct;
721 result.isalnum = str_8bit_isalnum;
722 result.isdigit = str_8bit_isdigit;
723 result.isprint = str_8bit_isprint;
724 result.iscombiningmark = str_8bit_iscombiningmark;
725 result.toupper = str_8bit_toupper;
726 result.tolower = str_8bit_tolower;
727 result.length = str_8bit_length;
728 result.length2 = str_8bit_length2;
729 result.length_noncomb = str_8bit_length;
730 result.fix_string = str_8bit_fix_string;
731 result.term_form = str_8bit_term_form;
732 result.fit_to_term = str_8bit_fit_to_term;
733 result.term_trim = str_8bit_term_trim;
734 result.term_width2 = str_8bit_term_width2;
735 result.term_width1 = str_8bit_term_width1;
736 result.term_char_width = str_8bit_term_char_width;
737 result.msg_term_size = str_8bit_msg_term_size;
738 result.term_substring = str_8bit_term_substring;
739 result.trunc = str_8bit_trunc;
740 result.offset_to_pos = str_8bit_offset_to_pos;
741 result.column_to_pos = str_8bit_column_to_pos;
742 result.create_search_needle = str_8bit_create_search_needle;
743 result.release_search_needle = str_8bit_release_search_needle;
744 result.search_first = str_8bit_search_first;
745 result.search_last = str_8bit_search_last;
746 result.compare = str_8bit_compare;
747 result.ncompare = str_8bit_ncompare;
748 result.casecmp = str_8bit_casecmp;
749 result.ncasecmp = str_8bit_ncasecmp;
750 result.prefix = str_8bit_prefix;
751 result.caseprefix = str_8bit_caseprefix;
752 result.create_key = str_8bit_create_key;
753 result.create_key_for_filename = str_8bit_create_key;
754 result.key_collate = str_8bit_key_collate;
755 result.release_key = str_8bit_release_key;
757 return result;