(edit_complete_word_cmd): make correct charset conversion
[midnight-commander.git] / lib / strutil / strutilascii.c
blob80d67d0ae2fe3d02f11cc09941d215c65529a687
1 /*
2 ASCII 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/>.
25 #include <config.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <config.h>
30 #include <errno.h>
31 #include "lib/global.h"
32 #include "lib/strutil.h"
34 /* using g_ascii function from glib
35 * on terminal are showed only ascii characters (lower then 0x80)
38 static const char replch = '?';
40 static void
41 str_ascii_insert_replace_char (GString * buffer)
43 g_string_append_c (buffer, replch);
46 static int
47 str_ascii_is_valid_string (const char *text)
49 (void) text;
50 return 1;
53 static int
54 str_ascii_is_valid_char (const char *ch, size_t size)
56 (void) ch;
57 (void) size;
58 return 1;
61 static void
62 str_ascii_cnext_char (const char **text)
64 (*text)++;
67 static void
68 str_ascii_cprev_char (const char **text)
70 (*text)--;
73 static int
74 str_ascii_cnext_noncomb_char (const char **text)
76 if (*text[0] != '\0')
78 (*text)++;
79 return 1;
81 else
82 return 0;
85 static int
86 str_ascii_cprev_noncomb_char (const char **text, const char *begin)
88 if ((*text) != begin)
90 (*text)--;
91 return 1;
93 else
94 return 0;
97 static int
98 str_ascii_isspace (const char *text)
100 return g_ascii_isspace ((gchar) text[0]);
103 static int
104 str_ascii_ispunct (const char *text)
106 return g_ascii_ispunct ((gchar) text[0]);
109 static int
110 str_ascii_isalnum (const char *text)
112 return g_ascii_isalnum ((gchar) text[0]);
115 static int
116 str_ascii_isdigit (const char *text)
118 return g_ascii_isdigit ((gchar) text[0]);
121 static int
122 str_ascii_isprint (const char *text)
124 return g_ascii_isprint ((gchar) text[0]);
127 static gboolean
128 str_ascii_iscombiningmark (const char *text)
130 (void) text;
131 return FALSE;
134 static int
135 str_ascii_toupper (const char *text, char **out, size_t * remain)
137 if (*remain <= 1)
138 return 0;
139 (*out)[0] = (char) g_ascii_toupper ((gchar) text[0]);
140 (*out)++;
141 (*remain)--;
142 return 1;
145 static int
146 str_ascii_tolower (const char *text, char **out, size_t * remain)
148 if (*remain <= 1)
149 return 0;
150 (*out)[0] = (char) g_ascii_tolower ((gchar) text[0]);
151 (*out)++;
152 (*remain)--;
153 return 1;
156 static int
157 str_ascii_length (const char *text)
159 return strlen (text);
162 static int
163 str_ascii_length2 (const char *text, int size)
165 return (size >= 0) ? min (strlen (text), (gsize) size) : strlen (text);
168 static gchar *
169 str_ascii_conv_gerror_message (GError * error, const char *def_msg)
171 /* the same as str_utf8_conv_gerror_message() */
172 if ((error != NULL) && (error->message != NULL))
173 return g_strdup (error->message);
175 return g_strdup (def_msg != NULL ? def_msg : "");
178 static estr_t
179 str_ascii_vfs_convert_to (GIConv coder, const char *string, int size, GString * buffer)
181 (void) coder;
182 g_string_append_len (buffer, string, size);
183 return ESTR_SUCCESS;
187 static const char *
188 str_ascii_term_form (const char *text)
190 static char result[BUF_MEDIUM];
191 char *actual;
192 size_t remain;
193 size_t length;
194 size_t pos = 0;
196 actual = result;
197 remain = sizeof (result);
198 length = strlen (text);
200 /* go throw all characters and check, if they are ascii and printable */
201 for (; pos < length && remain > 1; pos++, actual++, remain--)
203 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
204 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
207 actual[0] = '\0';
208 return result;
211 static const char *
212 str_ascii_fit_to_term (const char *text, int width, align_crt_t just_mode)
214 static char result[BUF_MEDIUM];
215 char *actual;
216 size_t remain;
217 int ident;
218 size_t length;
219 size_t pos = 0;
221 length = strlen (text);
222 actual = result;
223 remain = sizeof (result);
225 if ((int) length <= width)
227 ident = 0;
228 switch (HIDE_FIT (just_mode))
230 case J_CENTER_LEFT:
231 case J_CENTER:
232 ident = (width - length) / 2;
233 break;
234 case J_RIGHT:
235 ident = width - length;
236 break;
239 /* add space before text */
240 if ((int) remain <= ident)
241 goto finally;
242 memset (actual, ' ', ident);
243 actual += ident;
244 remain -= ident;
246 /* copy all characters */
247 for (; pos < (gsize) length && remain > 1; pos++, actual++, remain--)
249 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
250 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
253 /* add space after text */
254 if (width - length - ident > 0)
256 if (remain <= width - length - ident)
257 goto finally;
258 memset (actual, ' ', width - length - ident);
259 actual += width - length - ident;
262 else
264 if (IS_FIT (just_mode))
266 /* copy prefix of text, that is not wider than width / 2 */
267 for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--)
269 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
270 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
273 if (remain <= 1)
274 goto finally;
275 actual[0] = '~';
276 actual++;
277 remain--;
279 pos += length - width + 1;
281 /* copy suffix of text */
282 for (; pos < length && remain > 1; pos++, actual++, remain--)
284 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
285 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
288 else
290 ident = 0;
291 switch (HIDE_FIT (just_mode))
293 case J_CENTER:
294 ident = (length - width) / 2;
295 break;
296 case J_RIGHT:
297 ident = length - width;
298 break;
301 /* copy substring text, substring start from ident and take width
302 * characters from text */
303 pos += ident;
304 for (; pos < (gsize) (ident + width) && remain > 1; pos++, actual++, remain--)
306 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
307 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
312 finally:
313 actual[0] = '\0';
314 return result;
317 static const char *
318 str_ascii_term_trim (const char *text, int width)
320 static char result[BUF_MEDIUM];
321 size_t remain;
322 char *actual;
323 size_t pos = 0;
324 size_t length;
326 length = strlen (text);
327 actual = result;
328 remain = sizeof (result);
331 if (width > 0)
333 if (width < (int) length)
335 if (width <= 3)
337 memset (actual, '.', width);
338 actual += width;
340 else
342 memset (actual, '.', 3);
343 actual += 3;
344 remain -= 3;
346 pos += length - width + 3;
348 /* copy suffix of text */
349 for (; pos < length && remain > 1; pos++, actual++, remain--)
351 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
352 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
356 else
358 /* copy all characters */
359 for (; pos < length && remain > 1; pos++, actual++, remain--)
361 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
362 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
367 actual[0] = '\0';
368 return result;
371 static int
372 str_ascii_term_width2 (const char *text, size_t length)
374 return (length != (size_t) (-1)) ? min (strlen (text), length) : strlen (text);
377 static int
378 str_ascii_term_width1 (const char *text)
380 return str_ascii_term_width2 (text, (size_t) (-1));
383 static int
384 str_ascii_term_char_width (const char *text)
386 (void) text;
387 return 1;
390 static const char *
391 str_ascii_term_substring (const char *text, int start, int width)
393 static char result[BUF_MEDIUM];
394 size_t remain;
395 char *actual;
396 size_t pos = 0;
397 size_t length;
399 actual = result;
400 remain = sizeof (result);
401 length = strlen (text);
403 if (start < (int) length)
405 pos += start;
406 /* copy at most width characters from text from start */
407 for (; pos < length && width > 0 && remain > 1; pos++, width--, actual++, remain--)
410 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
411 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
415 /* if text is shorter then width, add space to the end */
416 for (; width > 0 && remain > 1; actual++, remain--, width--)
418 actual[0] = ' ';
421 actual[0] = '\0';
422 return result;
425 static const char *
426 str_ascii_trunc (const char *text, int width)
428 static char result[MC_MAXPATHLEN];
429 int remain;
430 char *actual;
431 size_t pos = 0;
432 size_t length;
434 actual = result;
435 remain = sizeof (result);
436 length = strlen (text);
438 if ((int) length > width)
440 /* copy prefix of text */
441 for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--)
443 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
444 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
447 if (remain <= 1)
448 goto finally;
449 actual[0] = '~';
450 actual++;
451 remain--;
453 pos += length - width + 1;
455 /* copy suffix of text */
456 for (; pos < length && remain > 1; pos++, actual++, remain--)
458 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
459 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
462 else
464 /* copy all characters */
465 for (; pos < length && remain > 1; pos++, actual++, remain--)
467 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
468 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
472 finally:
473 actual[0] = '\0';
474 return result;
477 static int
478 str_ascii_offset_to_pos (const char *text, size_t length)
480 (void) text;
481 return (int) length;
484 static int
485 str_ascii_column_to_pos (const char *text, size_t pos)
487 (void) text;
488 return (int) pos;
491 static char *
492 str_ascii_create_search_needle (const char *needle, int case_sen)
494 (void) case_sen;
495 return (char *) needle;
498 static void
499 str_ascii_release_search_needle (char *needle, int case_sen)
501 (void) case_sen;
502 (void) needle;
506 static const char *
507 str_ascii_search_first (const char *text, const char *search, int case_sen)
509 char *fold_text;
510 char *fold_search;
511 const char *match;
512 size_t offset;
514 fold_text = (case_sen) ? (char *) text : g_ascii_strdown (text, -1);
515 fold_search = (case_sen) ? (char *) search : g_ascii_strdown (search, -1);
517 match = g_strstr_len (fold_text, -1, fold_search);
518 if (match != NULL)
520 offset = match - fold_text;
521 match = text + offset;
524 if (!case_sen)
526 g_free (fold_text);
527 g_free (fold_search);
530 return match;
533 static const char *
534 str_ascii_search_last (const char *text, const char *search, int case_sen)
536 char *fold_text;
537 char *fold_search;
538 const char *match;
539 size_t offset;
541 fold_text = (case_sen) ? (char *) text : g_ascii_strdown (text, -1);
542 fold_search = (case_sen) ? (char *) search : g_ascii_strdown (search, -1);
544 match = g_strrstr_len (fold_text, -1, fold_search);
545 if (match != NULL)
547 offset = match - fold_text;
548 match = text + offset;
551 if (!case_sen)
553 g_free (fold_text);
554 g_free (fold_search);
557 return match;
560 static int
561 str_ascii_compare (const char *t1, const char *t2)
563 return strcmp (t1, t2);
566 static int
567 str_ascii_ncompare (const char *t1, const char *t2)
569 return strncmp (t1, t2, min (strlen (t1), strlen (t2)));
572 static int
573 str_ascii_casecmp (const char *t1, const char *t2)
575 return g_ascii_strcasecmp (t1, t2);
578 static int
579 str_ascii_ncasecmp (const char *t1, const char *t2)
581 return g_ascii_strncasecmp (t1, t2, min (strlen (t1), strlen (t2)));
584 static void
585 str_ascii_fix_string (char *text)
587 for (; text[0] != '\0'; text++)
589 text[0] = ((unsigned char) text[0] < 128) ? text[0] : '?';
593 static char *
594 str_ascii_create_key (const char *text, int case_sen)
596 (void) case_sen;
597 return (char *) text;
600 static int
601 str_ascii_key_collate (const char *t1, const char *t2, int case_sen)
603 return (case_sen) ? strcmp (t1, t2) : g_ascii_strcasecmp (t1, t2);
606 static void
607 str_ascii_release_key (char *key, int case_sen)
609 (void) key;
610 (void) case_sen;
613 static int
614 str_ascii_prefix (const char *text, const char *prefix)
616 int result;
617 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
618 && text[result] == prefix[result]; result++);
619 return result;
622 static int
623 str_ascii_caseprefix (const char *text, const char *prefix)
625 int result;
626 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
627 && g_ascii_toupper (text[result]) == g_ascii_toupper (prefix[result]); result++);
628 return result;
632 struct str_class
633 str_ascii_init (void)
635 struct str_class result;
637 result.conv_gerror_message = str_ascii_conv_gerror_message;
638 result.vfs_convert_to = str_ascii_vfs_convert_to;
639 result.insert_replace_char = str_ascii_insert_replace_char;
640 result.is_valid_string = str_ascii_is_valid_string;
641 result.is_valid_char = str_ascii_is_valid_char;
642 result.cnext_char = str_ascii_cnext_char;
643 result.cprev_char = str_ascii_cprev_char;
644 result.cnext_char_safe = str_ascii_cnext_char;
645 result.cprev_char_safe = str_ascii_cprev_char;
646 result.cnext_noncomb_char = str_ascii_cnext_noncomb_char;
647 result.cprev_noncomb_char = str_ascii_cprev_noncomb_char;
648 result.char_isspace = str_ascii_isspace;
649 result.char_ispunct = str_ascii_ispunct;
650 result.char_isalnum = str_ascii_isalnum;
651 result.char_isdigit = str_ascii_isdigit;
652 result.char_isprint = str_ascii_isprint;
653 result.char_iscombiningmark = str_ascii_iscombiningmark;
654 result.char_toupper = str_ascii_toupper;
655 result.char_tolower = str_ascii_tolower;
656 result.length = str_ascii_length;
657 result.length2 = str_ascii_length2;
658 result.length_noncomb = str_ascii_length;
659 result.fix_string = str_ascii_fix_string;
660 result.term_form = str_ascii_term_form;
661 result.fit_to_term = str_ascii_fit_to_term;
662 result.term_trim = str_ascii_term_trim;
663 result.term_width2 = str_ascii_term_width2;
664 result.term_width1 = str_ascii_term_width1;
665 result.term_char_width = str_ascii_term_char_width;
666 result.term_substring = str_ascii_term_substring;
667 result.trunc = str_ascii_trunc;
668 result.offset_to_pos = str_ascii_offset_to_pos;
669 result.column_to_pos = str_ascii_column_to_pos;
670 result.create_search_needle = str_ascii_create_search_needle;
671 result.release_search_needle = str_ascii_release_search_needle;
672 result.search_first = str_ascii_search_first;
673 result.search_last = str_ascii_search_last;
674 result.compare = str_ascii_compare;
675 result.ncompare = str_ascii_ncompare;
676 result.casecmp = str_ascii_casecmp;
677 result.ncasecmp = str_ascii_ncasecmp;
678 result.prefix = str_ascii_prefix;
679 result.caseprefix = str_ascii_caseprefix;
680 result.create_key = str_ascii_create_key;
681 result.create_key_for_filename = str_ascii_create_key;
682 result.key_collate = str_ascii_key_collate;
683 result.release_key = str_ascii_release_key;
685 return result;