Moved dir $(srcdir)/syntax into $(srcdir)/misc/syntax
[midnight-commander.git] / src / strutil8bit.c
blob4acd0d3d80de852c887453c11c7db68e26eda4ef
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 "global.h"
31 #include "strutil.h"
32 #include "fs.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 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)
72 static void
73 str_8bit_insert_replace_char (GString * buffer)
75 g_string_append_c (buffer, replch);
78 static int
79 str_8bit_is_valid_string (const char *text)
81 (void) text;
82 return 1;
85 static int
86 str_8bit_is_valid_char (const char *ch, size_t size)
88 (void) ch;
89 (void) size;
90 return 1;
93 static void
94 str_8bit_cnext_char (const char **text)
96 (*text)++;
99 static void
100 str_8bit_cprev_char (const char **text)
102 (*text)--;
105 static int
106 str_8bit_cnext_noncomb_char (const char **text)
108 if (*text[0] != '\0')
110 (*text)++;
111 return 1;
113 else
114 return 0;
117 static int
118 str_8bit_cprev_noncomb_char (const char **text, const char *begin)
120 if ((*text) != begin)
122 (*text)--;
123 return 1;
125 else
126 return 0;
129 static int
130 str_8bit_isspace (const char *text)
132 return char_isspace (text[0]);
135 static int
136 str_8bit_ispunct (const char *text)
138 return char_ispunct (text[0]);
141 static int
142 str_8bit_isalnum (const char *text)
144 return char_isalnum (text[0]);
147 static int
148 str_8bit_isdigit (const char *text)
150 return char_isdigit (text[0]);
153 static int
154 str_8bit_isprint (const char *text)
156 return char_isprint (text[0]);
159 static int
160 str_8bit_iscombiningmark (const char *text)
162 (void) text;
163 return 0;
166 static int
167 str_8bit_toupper (const char *text, char **out, size_t * remain)
169 if (*remain <= 1)
170 return 0;
171 (*out)[0] = char_toupper (text[0]);
172 (*out)++;
173 (*remain)--;
174 return 1;
177 static int
178 str_8bit_tolower (const char *text, char **out, size_t * remain)
180 if (*remain <= 1)
181 return 0;
182 (*out)[0] = char_tolower (text[0]);
183 (*out)++;
184 (*remain)--;
185 return 1;
188 static int
189 str_8bit_length (const char *text)
191 return strlen (text);
194 static int
195 str_8bit_length2 (const char *text, int size)
197 return (size >= 0) ? min (strlen (text), (gsize)size) : strlen (text);
200 static gchar *
201 str_8bit_conv_gerror_message (GError *error, const char *def_msg)
203 GIConv conv;
204 gchar *ret;
206 /* glib messages are in UTF-8 charset */
207 conv = str_crt_conv_from ("UTF-8");
209 if (conv == INVALID_CONV)
210 ret = g_strdup (def_msg != NULL ? def_msg : "");
211 else {
212 GString *buf;
214 buf = g_string_new ("");
216 if (str_convert (conv, error->message, buf) != ESTR_FAILURE) {
217 ret = buf->str;
218 g_string_free (buf, FALSE);
219 } else {
220 ret = g_strdup (def_msg != NULL ? def_msg : "");
221 g_string_free (buf, TRUE);
224 str_close_conv (conv);
227 return ret;
230 static estr_t
231 str_8bit_vfs_convert_to (GIConv coder, const char *string,
232 int size, GString * buffer)
234 estr_t result;
236 if (coder == str_cnv_not_convert)
238 g_string_append_len (buffer, string, size);
239 result = ESTR_SUCCESS;
241 else
242 result = str_nconvert (coder, (char *) string, size, buffer);
244 return result;
248 static const char *
249 str_8bit_term_form (const char *text)
251 static char result[BUF_MEDIUM];
252 char *actual;
253 size_t remain;
254 size_t length;
255 size_t pos = 0;
257 actual = result;
258 remain = sizeof (result);
259 length = strlen (text);
261 for (; pos < length && remain > 1; pos++, actual++, remain--)
263 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
266 actual[0] = '\0';
267 return result;
270 static const char *
271 str_8bit_fit_to_term (const char *text, int width, align_crt_t just_mode)
273 static char result[BUF_MEDIUM];
274 char *actual;
275 size_t remain;
276 int ident;
277 size_t length;
278 size_t pos = 0;
280 length = strlen (text);
281 actual = result;
282 remain = sizeof (result);
284 if ((int)length <= width)
286 ident = 0;
287 switch (HIDE_FIT (just_mode))
289 case J_CENTER_LEFT:
290 case J_CENTER:
291 ident = (width - length) / 2;
292 break;
293 case J_RIGHT:
294 ident = width - length;
295 break;
298 if ((int)remain <= ident)
299 goto finally;
300 memset (actual, ' ', ident);
301 actual += ident;
302 remain -= ident;
304 for (; pos < length && remain > 1; pos++, actual++, remain--)
306 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
308 if (width - length - ident > 0)
310 if (remain <= width - length - ident)
311 goto finally;
312 memset (actual, ' ', width - length - ident);
313 actual += width - length - ident;
314 remain -= width - length - ident;
317 else
319 if (IS_FIT (just_mode))
321 for (; pos + 1 <= (gsize)width / 2 && remain > 1;
322 actual++, pos++, remain--)
325 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
328 if (remain <= 1)
329 goto finally;
330 actual[0] = '~';
331 actual++;
332 remain--;
334 pos += length - width + 1;
336 for (; pos < length && remain > 1; pos++, actual++, remain--)
338 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
341 else
343 ident = 0;
344 switch (HIDE_FIT (just_mode))
346 case J_CENTER:
347 ident = (length - width) / 2;
348 break;
349 case J_RIGHT:
350 ident = length - width;
351 break;
354 pos += ident;
355 for (; pos < (gsize)(ident + width) && remain > 1;
356 pos++, actual++, remain--)
359 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
364 finally:
365 actual[0] = '\0';
366 return result;
369 static const char *
370 str_8bit_term_trim (const char *text, int width)
372 static char result[BUF_MEDIUM];
373 size_t remain;
374 char *actual;
375 size_t pos = 0;
376 size_t length;
378 length = strlen (text);
379 actual = result;
380 remain = sizeof (result);
382 if (width < (int)length)
384 if (width <= 3)
386 memset (actual, '.', width);
387 actual += width;
388 remain -= width;
390 else
392 memset (actual, '.', 3);
393 actual += 3;
394 remain -= 3;
396 pos += length - width + 3;
398 for (; pos < length && remain > 1; pos++, actual++, remain--)
400 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
404 else
406 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))
420 ? min (strlen (text), length) : strlen (text);
423 static int
424 str_8bit_term_width1 (const char *text)
426 return str_8bit_term_width2 (text, (size_t) (-1));
429 static int
430 str_8bit_term_char_width (const char *text)
432 (void) text;
433 return 1;
436 static void
437 str_8bit_msg_term_size (const char *text, int *lines, int *columns)
440 char *p, *tmp;
441 char *q;
442 char c = '\0';
443 int width;
445 (*lines) = 1;
446 (*columns) = 0;
447 tmp = g_strdup ((char *)text);
448 p = tmp;
449 for (;;)
451 q = strchr (p, '\n');
452 if (q != NULL)
454 c = q[0];
455 q[0] = '\0';
458 width = str_8bit_term_width1 (p);
459 if (width > (*columns))
460 (*columns) = width;
462 if (q == NULL)
463 break;
464 q[0] = c;
465 p = q + 1;
466 (*lines)++;
468 g_free (tmp);
471 static const char *
472 str_8bit_term_substring (const char *text, int start, int width)
474 static char result[BUF_MEDIUM];
475 size_t remain;
476 char *actual;
477 size_t pos = 0;
478 size_t length;
480 actual = result;
481 remain = sizeof (result);
482 length = strlen (text);
484 if (start < (int)length)
486 pos += start;
487 for (; pos < length && width > 0 && remain > 1;
488 pos++, width--, actual++, remain--)
491 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
495 for (; width > 0 && remain > 1; actual++, remain--, width--)
497 actual[0] = ' ';
500 actual[0] = '\0';
501 return result;
504 static const char *
505 str_8bit_trunc (const char *text, int width)
507 static char result[MC_MAXPATHLEN];
508 int remain;
509 char *actual;
510 size_t pos = 0;
511 size_t length;
513 actual = result;
514 remain = sizeof (result);
515 length = strlen (text);
517 if ((int)length > width)
519 for (; pos + 1 <= (gsize)width / 2 && remain > 1; actual++, pos++, remain--)
521 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
524 if (remain <= 1)
525 goto finally;
526 actual[0] = '~';
527 actual++;
528 remain--;
530 pos += length - width + 1;
532 for (; pos < length && remain > 1; pos++, actual++, remain--)
534 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
537 else
539 for (; pos < length && remain > 1; pos++, actual++, remain--)
541 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
545 finally:
546 actual[0] = '\0';
547 return result;
550 static int
551 str_8bit_offset_to_pos (const char *text, size_t length)
553 (void) text;
554 return (int) length;
557 static int
558 str_8bit_column_to_pos (const char *text, size_t pos)
560 (void) text;
561 return (int)pos;
564 static char *
565 str_8bit_create_search_needle (const char *needle, int case_sen)
567 (void) case_sen;
568 return (char *) needle;
571 static void
572 str_8bit_release_search_needle (char *needle, int case_sen)
574 (void) case_sen;
575 (void) needle;
578 static const char *
579 str_8bit_search_first (const char *text, const char *search, int case_sen)
581 char *fold_text;
582 char *fold_search;
583 const char *match;
584 size_t offsset;
586 fold_text = (case_sen) ? (char *) text : g_strdown (g_strdup (text));
587 fold_search = (case_sen) ? (char *) search : g_strdown (g_strdup (search));
589 match = g_strstr_len (fold_text, -1, fold_search);
590 if (match != NULL)
592 offsset = match - fold_text;
593 match = text + offsset;
596 if (!case_sen)
598 g_free (fold_text);
599 g_free (fold_search);
602 return match;
605 static const char *
606 str_8bit_search_last (const char *text, const char *search, int case_sen)
608 char *fold_text;
609 char *fold_search;
610 const char *match;
611 size_t offsset;
613 fold_text = (case_sen) ? (char *) text : g_strdown (g_strdup (text));
614 fold_search = (case_sen) ? (char *) search : g_strdown (g_strdup (search));
616 match = g_strrstr_len (fold_text, -1, fold_search);
617 if (match != NULL)
619 offsset = match - fold_text;
620 match = text + offsset;
623 if (!case_sen)
625 g_free (fold_text);
626 g_free (fold_search);
629 return match;
632 static int
633 str_8bit_compare (const char *t1, const char *t2)
635 return strcmp (t1, t2);
638 static int
639 str_8bit_ncompare (const char *t1, const char *t2)
641 return strncmp (t1, t2, min (strlen (t1), strlen (t2)));
644 static int
645 str_8bit_casecmp (const char *t1, const char *t2)
647 return g_strcasecmp (t1, t2);
650 static int
651 str_8bit_ncasecmp (const char *t1, const char *t2)
653 return g_strncasecmp (t1, t2, min (strlen (t1), strlen (t2)));
656 static int
657 str_8bit_prefix (const char *text, const char *prefix)
659 int result;
660 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
661 && text[result] == prefix[result]; result++);
662 return result;
665 static int
666 str_8bit_caseprefix (const char *text, const char *prefix)
668 int result;
669 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
670 && char_toupper (text[result]) == char_toupper (prefix[result]); result++);
671 return result;
676 static void
677 str_8bit_fix_string (char *text)
679 (void) text;
682 static char *
683 str_8bit_create_key (const char *text, int case_sen)
685 return (case_sen) ? (char *) text : g_strdown (g_strdup (text));
688 static int
689 str_8bit_key_collate (const char *t1, const char *t2, int case_sen)
691 if (case_sen)
692 return strcmp (t1, t2);
693 else
694 return strcoll (t1, t2);
697 static void
698 str_8bit_release_key (char *key, int case_sen)
700 if (!case_sen)
701 g_free (key);
704 struct str_class
705 str_8bit_init (void)
707 struct str_class result;
709 result.conv_gerror_message = str_8bit_conv_gerror_message;
710 result.vfs_convert_to = str_8bit_vfs_convert_to;
711 result.insert_replace_char = str_8bit_insert_replace_char;
712 result.is_valid_string = str_8bit_is_valid_string;
713 result.is_valid_char = str_8bit_is_valid_char;
714 result.cnext_char = str_8bit_cnext_char;
715 result.cprev_char = str_8bit_cprev_char;
716 result.cnext_char_safe = str_8bit_cnext_char;
717 result.cprev_char_safe = str_8bit_cprev_char;
718 result.cnext_noncomb_char = str_8bit_cnext_noncomb_char;
719 result.cprev_noncomb_char = str_8bit_cprev_noncomb_char;
720 result.isspace = str_8bit_isspace;
721 result.ispunct = str_8bit_ispunct;
722 result.isalnum = str_8bit_isalnum;
723 result.isdigit = str_8bit_isdigit;
724 result.isprint = str_8bit_isprint;
725 result.iscombiningmark = str_8bit_iscombiningmark;
726 result.toupper = str_8bit_toupper;
727 result.tolower = str_8bit_tolower;
728 result.length = str_8bit_length;
729 result.length2 = str_8bit_length2;
730 result.length_noncomb = str_8bit_length;
731 result.fix_string = str_8bit_fix_string;
732 result.term_form = str_8bit_term_form;
733 result.fit_to_term = str_8bit_fit_to_term;
734 result.term_trim = str_8bit_term_trim;
735 result.term_width2 = str_8bit_term_width2;
736 result.term_width1 = str_8bit_term_width1;
737 result.term_char_width = str_8bit_term_char_width;
738 result.msg_term_size = str_8bit_msg_term_size;
739 result.term_substring = str_8bit_term_substring;
740 result.trunc = str_8bit_trunc;
741 result.offset_to_pos = str_8bit_offset_to_pos;
742 result.column_to_pos = str_8bit_column_to_pos;
743 result.create_search_needle = str_8bit_create_search_needle;
744 result.release_search_needle = str_8bit_release_search_needle;
745 result.search_first = str_8bit_search_first;
746 result.search_last = str_8bit_search_last;
747 result.compare = str_8bit_compare;
748 result.ncompare = str_8bit_ncompare;
749 result.casecmp = str_8bit_casecmp;
750 result.ncasecmp = str_8bit_ncasecmp;
751 result.prefix = str_8bit_prefix;
752 result.caseprefix = str_8bit_caseprefix;
753 result.create_key = str_8bit_create_key;
754 result.create_key_for_filename = str_8bit_create_key;
755 result.key_collate = str_8bit_key_collate;
756 result.release_key = str_8bit_release_key;
758 return result;