fixed relative symlink operations. Symlink now stay relative
[midnight-commander.git] / lib / strutil / strutilascii.c
blob413e5a1cfa196529aa974b9cc0e4dd88629fcfa8
1 /* ASCII 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.
24 #include <config.h>
26 #include <stdio.h>
27 #include <ctype.h>
28 #include <config.h>
29 #include <errno.h>
30 #include "lib/global.h"
31 #include "lib/strutil.h"
33 /* using g_ascii function from glib
34 * on terminal are showed only ascii characters (lower then 0x80)
37 static const char replch = '?';
39 static void
40 str_ascii_insert_replace_char (GString * buffer)
42 g_string_append_c (buffer, replch);
45 static int
46 str_ascii_is_valid_string (const char *text)
48 (void) text;
49 return 1;
52 static int
53 str_ascii_is_valid_char (const char *ch, size_t size)
55 (void) ch;
56 (void) size;
57 return 1;
60 static void
61 str_ascii_cnext_char (const char **text)
63 (*text)++;
66 static void
67 str_ascii_cprev_char (const char **text)
69 (*text)--;
72 static int
73 str_ascii_cnext_noncomb_char (const char **text)
75 if (*text[0] != '\0')
77 (*text)++;
78 return 1;
80 else
81 return 0;
84 static int
85 str_ascii_cprev_noncomb_char (const char **text, const char *begin)
87 if ((*text) != begin)
89 (*text)--;
90 return 1;
92 else
93 return 0;
96 static int
97 str_ascii_isspace (const char *text)
99 return g_ascii_isspace ((gchar) text[0]);
102 static int
103 str_ascii_ispunct (const char *text)
105 return g_ascii_ispunct ((gchar) text[0]);
108 static int
109 str_ascii_isalnum (const char *text)
111 return g_ascii_isalnum ((gchar) text[0]);
114 static int
115 str_ascii_isdigit (const char *text)
117 return g_ascii_isdigit ((gchar) text[0]);
120 static int
121 str_ascii_isprint (const char *text)
123 return g_ascii_isprint ((gchar) text[0]);
126 static int
127 str_ascii_iscombiningmark (const char *text)
129 (void) text;
130 return 0;
133 static int
134 str_ascii_toupper (const char *text, char **out, size_t * remain)
136 if (*remain <= 1)
137 return 0;
138 (*out)[0] = (char) g_ascii_toupper ((gchar) text[0]);
139 (*out)++;
140 (*remain)--;
141 return 1;
144 static int
145 str_ascii_tolower (const char *text, char **out, size_t * remain)
147 if (*remain <= 1)
148 return 0;
149 (*out)[0] = (char) g_ascii_tolower ((gchar) text[0]);
150 (*out)++;
151 (*remain)--;
152 return 1;
155 static int
156 str_ascii_length (const char *text)
158 return strlen (text);
161 static int
162 str_ascii_length2 (const char *text, int size)
164 return (size >= 0) ? min (strlen (text), (gsize) size) : strlen (text);
167 static gchar *
168 str_ascii_conv_gerror_message (GError * error, const char *def_msg)
170 /* the same as str_utf8_conv_gerror_message() */
171 if ((error != NULL) && (error->message != NULL))
172 return g_strdup (error->message);
174 return g_strdup (def_msg != NULL ? def_msg : "");
177 static estr_t
178 str_ascii_vfs_convert_to (GIConv coder, const char *string, int size, GString * buffer)
180 (void) coder;
181 g_string_append_len (buffer, string, size);
182 return ESTR_SUCCESS;
186 static const char *
187 str_ascii_term_form (const char *text)
189 static char result[BUF_MEDIUM];
190 char *actual;
191 size_t remain;
192 size_t length;
193 size_t pos = 0;
195 actual = result;
196 remain = sizeof (result);
197 length = strlen (text);
199 /* go throw all characters and check, if they are ascii and printable */
200 for (; pos < length && remain > 1; pos++, actual++, remain--)
202 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
203 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
206 actual[0] = '\0';
207 return result;
210 static const char *
211 str_ascii_fit_to_term (const char *text, int width, align_crt_t just_mode)
213 static char result[BUF_MEDIUM];
214 char *actual;
215 size_t remain;
216 int ident;
217 size_t length;
218 size_t pos = 0;
220 length = strlen (text);
221 actual = result;
222 remain = sizeof (result);
224 if ((int) length <= width)
226 ident = 0;
227 switch (HIDE_FIT (just_mode))
229 case J_CENTER_LEFT:
230 case J_CENTER:
231 ident = (width - length) / 2;
232 break;
233 case J_RIGHT:
234 ident = width - length;
235 break;
238 /* add space before text */
239 if ((int) remain <= ident)
240 goto finally;
241 memset (actual, ' ', ident);
242 actual += ident;
243 remain -= ident;
245 /* copy all characters */
246 for (; pos < (gsize) length && remain > 1; pos++, actual++, remain--)
248 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
249 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
252 /* add space after text */
253 if (width - length - ident > 0)
255 if (remain <= width - length - ident)
256 goto finally;
257 memset (actual, ' ', width - length - ident);
258 actual += width - length - ident;
259 remain -= 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);
330 if (width < (int) length)
332 if (width <= 3)
334 memset (actual, '.', width);
335 actual += width;
336 remain -= width;
338 else
340 memset (actual, '.', 3);
341 actual += 3;
342 remain -= 3;
344 pos += length - width + 3;
346 /* copy suffix of text */
347 for (; pos < length && remain > 1; pos++, actual++, remain--)
349 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
350 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
354 else
356 /* copy all characters */
357 for (; pos < length && remain > 1; pos++, actual++, remain--)
359 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
360 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
364 actual[0] = '\0';
365 return result;
368 static int
369 str_ascii_term_width2 (const char *text, size_t length)
371 return (length != (size_t) (-1)) ? min (strlen (text), length) : strlen (text);
374 static int
375 str_ascii_term_width1 (const char *text)
377 return str_ascii_term_width2 (text, (size_t) (-1));
380 static int
381 str_ascii_term_char_width (const char *text)
383 (void) text;
384 return 1;
387 static const char *
388 str_ascii_term_substring (const char *text, int start, int width)
390 static char result[BUF_MEDIUM];
391 size_t remain;
392 char *actual;
393 size_t pos = 0;
394 size_t length;
396 actual = result;
397 remain = sizeof (result);
398 length = strlen (text);
400 if (start < (int) length)
402 pos += start;
403 /* copy at most width characters from text from start */
404 for (; pos < length && width > 0 && remain > 1; pos++, width--, actual++, remain--)
407 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
408 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
412 /* if text is shorter then width, add space to the end */
413 for (; width > 0 && remain > 1; actual++, remain--, width--)
415 actual[0] = ' ';
418 actual[0] = '\0';
419 return result;
422 static const char *
423 str_ascii_trunc (const char *text, int width)
425 static char result[MC_MAXPATHLEN];
426 int remain;
427 char *actual;
428 size_t pos = 0;
429 size_t length;
431 actual = result;
432 remain = sizeof (result);
433 length = strlen (text);
435 if ((int) length > width)
437 /* copy prefix of text */
438 for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--)
440 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
441 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
444 if (remain <= 1)
445 goto finally;
446 actual[0] = '~';
447 actual++;
448 remain--;
450 pos += length - width + 1;
452 /* copy suffix of text */
453 for (; pos < length && remain > 1; pos++, actual++, remain--)
455 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
456 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
459 else
461 /* copy all characters */
462 for (; pos < length && remain > 1; pos++, actual++, remain--)
464 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
465 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
469 finally:
470 actual[0] = '\0';
471 return result;
474 static int
475 str_ascii_offset_to_pos (const char *text, size_t length)
477 (void) text;
478 return (int) length;
481 static int
482 str_ascii_column_to_pos (const char *text, size_t pos)
484 (void) text;
485 return (int) pos;
488 static char *
489 str_ascii_create_search_needle (const char *needle, int case_sen)
491 (void) case_sen;
492 return (char *) needle;
495 static void
496 str_ascii_release_search_needle (char *needle, int case_sen)
498 (void) case_sen;
499 (void) needle;
503 static const char *
504 str_ascii_search_first (const char *text, const char *search, int case_sen)
506 char *fold_text;
507 char *fold_search;
508 const char *match;
509 size_t offset;
511 fold_text = (case_sen) ? (char *) text : g_ascii_strdown (text, -1);
512 fold_search = (case_sen) ? (char *) search : g_ascii_strdown (search, -1);
514 match = g_strstr_len (fold_text, -1, fold_search);
515 if (match != NULL)
517 offset = match - fold_text;
518 match = text + offset;
521 if (!case_sen)
523 g_free (fold_text);
524 g_free (fold_search);
527 return match;
530 static const char *
531 str_ascii_search_last (const char *text, const char *search, int case_sen)
533 char *fold_text;
534 char *fold_search;
535 const char *match;
536 size_t offset;
538 fold_text = (case_sen) ? (char *) text : g_ascii_strdown (text, -1);
539 fold_search = (case_sen) ? (char *) search : g_ascii_strdown (search, -1);
541 match = g_strrstr_len (fold_text, -1, fold_search);
542 if (match != NULL)
544 offset = match - fold_text;
545 match = text + offset;
548 if (!case_sen)
550 g_free (fold_text);
551 g_free (fold_search);
554 return match;
557 static int
558 str_ascii_compare (const char *t1, const char *t2)
560 return strcmp (t1, t2);
563 static int
564 str_ascii_ncompare (const char *t1, const char *t2)
566 return strncmp (t1, t2, min (strlen (t1), strlen (t2)));
569 static int
570 str_ascii_casecmp (const char *t1, const char *t2)
572 return g_ascii_strcasecmp (t1, t2);
575 static int
576 str_ascii_ncasecmp (const char *t1, const char *t2)
578 return g_ascii_strncasecmp (t1, t2, min (strlen (t1), strlen (t2)));
581 static void
582 str_ascii_fix_string (char *text)
584 for (; text[0] != '\0'; text++)
586 text[0] = ((unsigned char) text[0] < 128) ? text[0] : '?';
590 static char *
591 str_ascii_create_key (const char *text, int case_sen)
593 (void) case_sen;
594 return (char *) text;
597 static int
598 str_ascii_key_collate (const char *t1, const char *t2, int case_sen)
600 return (case_sen) ? strcmp (t1, t2) : g_ascii_strcasecmp (t1, t2);
603 static void
604 str_ascii_release_key (char *key, int case_sen)
606 (void) key;
607 (void) case_sen;
610 static int
611 str_ascii_prefix (const char *text, const char *prefix)
613 int result;
614 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
615 && text[result] == prefix[result]; result++);
616 return result;
619 static int
620 str_ascii_caseprefix (const char *text, const char *prefix)
622 int result;
623 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
624 && g_ascii_toupper (text[result]) == g_ascii_toupper (prefix[result]); result++);
625 return result;
629 struct str_class
630 str_ascii_init (void)
632 struct str_class result;
634 result.conv_gerror_message = str_ascii_conv_gerror_message;
635 result.vfs_convert_to = str_ascii_vfs_convert_to;
636 result.insert_replace_char = str_ascii_insert_replace_char;
637 result.is_valid_string = str_ascii_is_valid_string;
638 result.is_valid_char = str_ascii_is_valid_char;
639 result.cnext_char = str_ascii_cnext_char;
640 result.cprev_char = str_ascii_cprev_char;
641 result.cnext_char_safe = str_ascii_cnext_char;
642 result.cprev_char_safe = str_ascii_cprev_char;
643 result.cnext_noncomb_char = str_ascii_cnext_noncomb_char;
644 result.cprev_noncomb_char = str_ascii_cprev_noncomb_char;
645 result.isspace = str_ascii_isspace;
646 result.ispunct = str_ascii_ispunct;
647 result.isalnum = str_ascii_isalnum;
648 result.isdigit = str_ascii_isdigit;
649 result.isprint = str_ascii_isprint;
650 result.iscombiningmark = str_ascii_iscombiningmark;
651 result.toupper = str_ascii_toupper;
652 result.tolower = str_ascii_tolower;
653 result.length = str_ascii_length;
654 result.length2 = str_ascii_length2;
655 result.length_noncomb = str_ascii_length;
656 result.fix_string = str_ascii_fix_string;
657 result.term_form = str_ascii_term_form;
658 result.fit_to_term = str_ascii_fit_to_term;
659 result.term_trim = str_ascii_term_trim;
660 result.term_width2 = str_ascii_term_width2;
661 result.term_width1 = str_ascii_term_width1;
662 result.term_char_width = str_ascii_term_char_width;
663 result.term_substring = str_ascii_term_substring;
664 result.trunc = str_ascii_trunc;
665 result.offset_to_pos = str_ascii_offset_to_pos;
666 result.column_to_pos = str_ascii_column_to_pos;
667 result.create_search_needle = str_ascii_create_search_needle;
668 result.release_search_needle = str_ascii_release_search_needle;
669 result.search_first = str_ascii_search_first;
670 result.search_last = str_ascii_search_last;
671 result.compare = str_ascii_compare;
672 result.ncompare = str_ascii_ncompare;
673 result.casecmp = str_ascii_casecmp;
674 result.ncasecmp = str_ascii_ncasecmp;
675 result.prefix = str_ascii_prefix;
676 result.caseprefix = str_ascii_caseprefix;
677 result.create_key = str_ascii_create_key;
678 result.create_key_for_filename = str_ascii_create_key;
679 result.key_collate = str_ascii_key_collate;
680 result.release_key = str_ascii_release_key;
682 return result;