Ticket #2918: cygwin test failure.
[midnight-commander.git] / lib / strutil / strutilascii.c
blob2186c42aa4a183b888b10a8c63eb40ff51bcd3a4
1 /*
2 ASCII strings utilities
4 Copyright (C) 2007, 2011
5 The Free Software Foundation, Inc.
7 Written by:
8 Rostislav Benes, 2007
10 The file_date routine is mostly from GNU's fileutils package,
11 written by Richard Stallman and David MacKenzie.
13 This file is part of the Midnight Commander.
15 The Midnight Commander is free software: you can redistribute it
16 and/or modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation, either version 3 of the License,
18 or (at your option) any later version.
20 The Midnight Commander is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include <config.h>
30 #include <stdio.h>
31 #include <ctype.h>
32 #include <config.h>
33 #include <errno.h>
34 #include "lib/global.h"
35 #include "lib/strutil.h"
37 /* using g_ascii function from glib
38 * on terminal are showed only ascii characters (lower then 0x80)
41 static const char replch = '?';
43 static void
44 str_ascii_insert_replace_char (GString * buffer)
46 g_string_append_c (buffer, replch);
49 static int
50 str_ascii_is_valid_string (const char *text)
52 (void) text;
53 return 1;
56 static int
57 str_ascii_is_valid_char (const char *ch, size_t size)
59 (void) ch;
60 (void) size;
61 return 1;
64 static void
65 str_ascii_cnext_char (const char **text)
67 (*text)++;
70 static void
71 str_ascii_cprev_char (const char **text)
73 (*text)--;
76 static int
77 str_ascii_cnext_noncomb_char (const char **text)
79 if (*text[0] != '\0')
81 (*text)++;
82 return 1;
84 else
85 return 0;
88 static int
89 str_ascii_cprev_noncomb_char (const char **text, const char *begin)
91 if ((*text) != begin)
93 (*text)--;
94 return 1;
96 else
97 return 0;
100 static int
101 str_ascii_isspace (const char *text)
103 return g_ascii_isspace ((gchar) text[0]);
106 static int
107 str_ascii_ispunct (const char *text)
109 return g_ascii_ispunct ((gchar) text[0]);
112 static int
113 str_ascii_isalnum (const char *text)
115 return g_ascii_isalnum ((gchar) text[0]);
118 static int
119 str_ascii_isdigit (const char *text)
121 return g_ascii_isdigit ((gchar) text[0]);
124 static int
125 str_ascii_isprint (const char *text)
127 return g_ascii_isprint ((gchar) text[0]);
130 static int
131 str_ascii_iscombiningmark (const char *text)
133 (void) text;
134 return 0;
137 static int
138 str_ascii_toupper (const char *text, char **out, size_t * remain)
140 if (*remain <= 1)
141 return 0;
142 (*out)[0] = (char) g_ascii_toupper ((gchar) text[0]);
143 (*out)++;
144 (*remain)--;
145 return 1;
148 static int
149 str_ascii_tolower (const char *text, char **out, size_t * remain)
151 if (*remain <= 1)
152 return 0;
153 (*out)[0] = (char) g_ascii_tolower ((gchar) text[0]);
154 (*out)++;
155 (*remain)--;
156 return 1;
159 static int
160 str_ascii_length (const char *text)
162 return strlen (text);
165 static int
166 str_ascii_length2 (const char *text, int size)
168 return (size >= 0) ? min (strlen (text), (gsize) size) : strlen (text);
171 static gchar *
172 str_ascii_conv_gerror_message (GError * error, const char *def_msg)
174 /* the same as str_utf8_conv_gerror_message() */
175 if ((error != NULL) && (error->message != NULL))
176 return g_strdup (error->message);
178 return g_strdup (def_msg != NULL ? def_msg : "");
181 static estr_t
182 str_ascii_vfs_convert_to (GIConv coder, const char *string, int size, GString * buffer)
184 (void) coder;
185 g_string_append_len (buffer, string, size);
186 return ESTR_SUCCESS;
190 static const char *
191 str_ascii_term_form (const char *text)
193 static char result[BUF_MEDIUM];
194 char *actual;
195 size_t remain;
196 size_t length;
197 size_t pos = 0;
199 actual = result;
200 remain = sizeof (result);
201 length = strlen (text);
203 /* go throw all characters and check, if they are ascii and printable */
204 for (; pos < length && remain > 1; pos++, actual++, remain--)
206 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
207 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
210 actual[0] = '\0';
211 return result;
214 static const char *
215 str_ascii_fit_to_term (const char *text, int width, align_crt_t just_mode)
217 static char result[BUF_MEDIUM];
218 char *actual;
219 size_t remain;
220 int ident;
221 size_t length;
222 size_t pos = 0;
224 length = strlen (text);
225 actual = result;
226 remain = sizeof (result);
228 if ((int) length <= width)
230 ident = 0;
231 switch (HIDE_FIT (just_mode))
233 case J_CENTER_LEFT:
234 case J_CENTER:
235 ident = (width - length) / 2;
236 break;
237 case J_RIGHT:
238 ident = width - length;
239 break;
242 /* add space before text */
243 if ((int) remain <= ident)
244 goto finally;
245 memset (actual, ' ', ident);
246 actual += ident;
247 remain -= ident;
249 /* copy all characters */
250 for (; pos < (gsize) length && remain > 1; pos++, actual++, remain--)
252 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
253 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
256 /* add space after text */
257 if (width - length - ident > 0)
259 if (remain <= width - length - ident)
260 goto finally;
261 memset (actual, ' ', width - length - ident);
262 actual += width - length - ident;
265 else
267 if (IS_FIT (just_mode))
269 /* copy prefix of text, that is not wider than width / 2 */
270 for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--)
272 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
273 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
276 if (remain <= 1)
277 goto finally;
278 actual[0] = '~';
279 actual++;
280 remain--;
282 pos += length - width + 1;
284 /* copy suffix of text */
285 for (; pos < length && remain > 1; pos++, actual++, remain--)
287 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
288 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
291 else
293 ident = 0;
294 switch (HIDE_FIT (just_mode))
296 case J_CENTER:
297 ident = (length - width) / 2;
298 break;
299 case J_RIGHT:
300 ident = length - width;
301 break;
304 /* copy substring text, substring start from ident and take width
305 * characters from text */
306 pos += ident;
307 for (; pos < (gsize) (ident + width) && remain > 1; pos++, actual++, remain--)
309 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
310 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
315 finally:
316 actual[0] = '\0';
317 return result;
320 static const char *
321 str_ascii_term_trim (const char *text, int width)
323 static char result[BUF_MEDIUM];
324 size_t remain;
325 char *actual;
326 size_t pos = 0;
327 size_t length;
329 length = strlen (text);
330 actual = result;
331 remain = sizeof (result);
334 if (width > 0)
336 if (width < (int) length)
338 if (width <= 3)
340 memset (actual, '.', width);
341 actual += width;
343 else
345 memset (actual, '.', 3);
346 actual += 3;
347 remain -= 3;
349 pos += length - width + 3;
351 /* copy suffix of text */
352 for (; pos < length && remain > 1; pos++, actual++, remain--)
354 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
355 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
359 else
361 /* copy all characters */
362 for (; pos < length && remain > 1; pos++, actual++, remain--)
364 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
365 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
370 actual[0] = '\0';
371 return result;
374 static int
375 str_ascii_term_width2 (const char *text, size_t length)
377 return (length != (size_t) (-1)) ? min (strlen (text), length) : strlen (text);
380 static int
381 str_ascii_term_width1 (const char *text)
383 return str_ascii_term_width2 (text, (size_t) (-1));
386 static int
387 str_ascii_term_char_width (const char *text)
389 (void) text;
390 return 1;
393 static const char *
394 str_ascii_term_substring (const char *text, int start, int width)
396 static char result[BUF_MEDIUM];
397 size_t remain;
398 char *actual;
399 size_t pos = 0;
400 size_t length;
402 actual = result;
403 remain = sizeof (result);
404 length = strlen (text);
406 if (start < (int) length)
408 pos += start;
409 /* copy at most width characters from text from start */
410 for (; pos < length && width > 0 && remain > 1; pos++, width--, actual++, remain--)
413 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
414 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
418 /* if text is shorter then width, add space to the end */
419 for (; width > 0 && remain > 1; actual++, remain--, width--)
421 actual[0] = ' ';
424 actual[0] = '\0';
425 return result;
428 static const char *
429 str_ascii_trunc (const char *text, int width)
431 static char result[MC_MAXPATHLEN];
432 int remain;
433 char *actual;
434 size_t pos = 0;
435 size_t length;
437 actual = result;
438 remain = sizeof (result);
439 length = strlen (text);
441 if ((int) length > width)
443 /* copy prefix of text */
444 for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--)
446 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
447 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
450 if (remain <= 1)
451 goto finally;
452 actual[0] = '~';
453 actual++;
454 remain--;
456 pos += length - width + 1;
458 /* copy suffix of text */
459 for (; pos < length && remain > 1; pos++, actual++, remain--)
461 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
462 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
465 else
467 /* copy all characters */
468 for (; pos < length && remain > 1; pos++, actual++, remain--)
470 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
471 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
475 finally:
476 actual[0] = '\0';
477 return result;
480 static int
481 str_ascii_offset_to_pos (const char *text, size_t length)
483 (void) text;
484 return (int) length;
487 static int
488 str_ascii_column_to_pos (const char *text, size_t pos)
490 (void) text;
491 return (int) pos;
494 static char *
495 str_ascii_create_search_needle (const char *needle, int case_sen)
497 (void) case_sen;
498 return (char *) needle;
501 static void
502 str_ascii_release_search_needle (char *needle, int case_sen)
504 (void) case_sen;
505 (void) needle;
509 static const char *
510 str_ascii_search_first (const char *text, const char *search, int case_sen)
512 char *fold_text;
513 char *fold_search;
514 const char *match;
515 size_t offset;
517 fold_text = (case_sen) ? (char *) text : g_ascii_strdown (text, -1);
518 fold_search = (case_sen) ? (char *) search : g_ascii_strdown (search, -1);
520 match = g_strstr_len (fold_text, -1, fold_search);
521 if (match != NULL)
523 offset = match - fold_text;
524 match = text + offset;
527 if (!case_sen)
529 g_free (fold_text);
530 g_free (fold_search);
533 return match;
536 static const char *
537 str_ascii_search_last (const char *text, const char *search, int case_sen)
539 char *fold_text;
540 char *fold_search;
541 const char *match;
542 size_t offset;
544 fold_text = (case_sen) ? (char *) text : g_ascii_strdown (text, -1);
545 fold_search = (case_sen) ? (char *) search : g_ascii_strdown (search, -1);
547 match = g_strrstr_len (fold_text, -1, fold_search);
548 if (match != NULL)
550 offset = match - fold_text;
551 match = text + offset;
554 if (!case_sen)
556 g_free (fold_text);
557 g_free (fold_search);
560 return match;
563 static int
564 str_ascii_compare (const char *t1, const char *t2)
566 return strcmp (t1, t2);
569 static int
570 str_ascii_ncompare (const char *t1, const char *t2)
572 return strncmp (t1, t2, min (strlen (t1), strlen (t2)));
575 static int
576 str_ascii_casecmp (const char *t1, const char *t2)
578 return g_ascii_strcasecmp (t1, t2);
581 static int
582 str_ascii_ncasecmp (const char *t1, const char *t2)
584 return g_ascii_strncasecmp (t1, t2, min (strlen (t1), strlen (t2)));
587 static void
588 str_ascii_fix_string (char *text)
590 for (; text[0] != '\0'; text++)
592 text[0] = ((unsigned char) text[0] < 128) ? text[0] : '?';
596 static char *
597 str_ascii_create_key (const char *text, int case_sen)
599 (void) case_sen;
600 return (char *) text;
603 static int
604 str_ascii_key_collate (const char *t1, const char *t2, int case_sen)
606 return (case_sen) ? strcmp (t1, t2) : g_ascii_strcasecmp (t1, t2);
609 static void
610 str_ascii_release_key (char *key, int case_sen)
612 (void) key;
613 (void) case_sen;
616 static int
617 str_ascii_prefix (const char *text, const char *prefix)
619 int result;
620 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
621 && text[result] == prefix[result]; result++);
622 return result;
625 static int
626 str_ascii_caseprefix (const char *text, const char *prefix)
628 int result;
629 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
630 && g_ascii_toupper (text[result]) == g_ascii_toupper (prefix[result]); result++);
631 return result;
635 struct str_class
636 str_ascii_init (void)
638 struct str_class result;
640 result.conv_gerror_message = str_ascii_conv_gerror_message;
641 result.vfs_convert_to = str_ascii_vfs_convert_to;
642 result.insert_replace_char = str_ascii_insert_replace_char;
643 result.is_valid_string = str_ascii_is_valid_string;
644 result.is_valid_char = str_ascii_is_valid_char;
645 result.cnext_char = str_ascii_cnext_char;
646 result.cprev_char = str_ascii_cprev_char;
647 result.cnext_char_safe = str_ascii_cnext_char;
648 result.cprev_char_safe = str_ascii_cprev_char;
649 result.cnext_noncomb_char = str_ascii_cnext_noncomb_char;
650 result.cprev_noncomb_char = str_ascii_cprev_noncomb_char;
651 result.isspace = str_ascii_isspace;
652 result.ispunct = str_ascii_ispunct;
653 result.isalnum = str_ascii_isalnum;
654 result.isdigit = str_ascii_isdigit;
655 result.isprint = str_ascii_isprint;
656 result.iscombiningmark = str_ascii_iscombiningmark;
657 result.toupper = str_ascii_toupper;
658 result.tolower = str_ascii_tolower;
659 result.length = str_ascii_length;
660 result.length2 = str_ascii_length2;
661 result.length_noncomb = str_ascii_length;
662 result.fix_string = str_ascii_fix_string;
663 result.term_form = str_ascii_term_form;
664 result.fit_to_term = str_ascii_fit_to_term;
665 result.term_trim = str_ascii_term_trim;
666 result.term_width2 = str_ascii_term_width2;
667 result.term_width1 = str_ascii_term_width1;
668 result.term_char_width = str_ascii_term_char_width;
669 result.term_substring = str_ascii_term_substring;
670 result.trunc = str_ascii_trunc;
671 result.offset_to_pos = str_ascii_offset_to_pos;
672 result.column_to_pos = str_ascii_column_to_pos;
673 result.create_search_needle = str_ascii_create_search_needle;
674 result.release_search_needle = str_ascii_release_search_needle;
675 result.search_first = str_ascii_search_first;
676 result.search_last = str_ascii_search_last;
677 result.compare = str_ascii_compare;
678 result.ncompare = str_ascii_ncompare;
679 result.casecmp = str_ascii_casecmp;
680 result.ncasecmp = str_ascii_ncasecmp;
681 result.prefix = str_ascii_prefix;
682 result.caseprefix = str_ascii_caseprefix;
683 result.create_key = str_ascii_create_key;
684 result.create_key_for_filename = str_ascii_create_key;
685 result.key_collate = str_ascii_key_collate;
686 result.release_key = str_ascii_release_key;
688 return result;