Ticket 1551: Update GPL version from 2 to 3
[midnight-commander.git] / lib / strutil / strutilascii.c
blob778fdcc765581f203c50a8cebd5d482b9a8b6c75
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;
263 remain -= width - length - ident;
266 else
268 if (IS_FIT (just_mode))
270 /* copy prefix of text, that is not wider than width / 2 */
271 for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--)
273 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
274 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
277 if (remain <= 1)
278 goto finally;
279 actual[0] = '~';
280 actual++;
281 remain--;
283 pos += length - width + 1;
285 /* copy suffix of text */
286 for (; pos < length && remain > 1; pos++, actual++, remain--)
288 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
289 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
292 else
294 ident = 0;
295 switch (HIDE_FIT (just_mode))
297 case J_CENTER:
298 ident = (length - width) / 2;
299 break;
300 case J_RIGHT:
301 ident = length - width;
302 break;
305 /* copy substring text, substring start from ident and take width
306 * characters from text */
307 pos += ident;
308 for (; pos < (gsize) (ident + width) && remain > 1; pos++, actual++, remain--)
310 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
311 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
316 finally:
317 actual[0] = '\0';
318 return result;
321 static const char *
322 str_ascii_term_trim (const char *text, int width)
324 static char result[BUF_MEDIUM];
325 size_t remain;
326 char *actual;
327 size_t pos = 0;
328 size_t length;
330 length = strlen (text);
331 actual = result;
332 remain = sizeof (result);
335 if (width > 0)
337 if (width < (int) length)
339 if (width <= 3)
341 memset (actual, '.', width);
342 actual += width;
343 remain -= width;
345 else
347 memset (actual, '.', 3);
348 actual += 3;
349 remain -= 3;
351 pos += length - width + 3;
353 /* copy suffix of text */
354 for (; pos < length && remain > 1; pos++, actual++, remain--)
356 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
357 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
361 else
363 /* copy all characters */
364 for (; pos < length && remain > 1; pos++, actual++, remain--)
366 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
367 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
372 actual[0] = '\0';
373 return result;
376 static int
377 str_ascii_term_width2 (const char *text, size_t length)
379 return (length != (size_t) (-1)) ? min (strlen (text), length) : strlen (text);
382 static int
383 str_ascii_term_width1 (const char *text)
385 return str_ascii_term_width2 (text, (size_t) (-1));
388 static int
389 str_ascii_term_char_width (const char *text)
391 (void) text;
392 return 1;
395 static const char *
396 str_ascii_term_substring (const char *text, int start, int width)
398 static char result[BUF_MEDIUM];
399 size_t remain;
400 char *actual;
401 size_t pos = 0;
402 size_t length;
404 actual = result;
405 remain = sizeof (result);
406 length = strlen (text);
408 if (start < (int) length)
410 pos += start;
411 /* copy at most width characters from text from start */
412 for (; pos < length && width > 0 && remain > 1; pos++, width--, actual++, remain--)
415 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
416 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
420 /* if text is shorter then width, add space to the end */
421 for (; width > 0 && remain > 1; actual++, remain--, width--)
423 actual[0] = ' ';
426 actual[0] = '\0';
427 return result;
430 static const char *
431 str_ascii_trunc (const char *text, int width)
433 static char result[MC_MAXPATHLEN];
434 int remain;
435 char *actual;
436 size_t pos = 0;
437 size_t length;
439 actual = result;
440 remain = sizeof (result);
441 length = strlen (text);
443 if ((int) length > width)
445 /* copy prefix of text */
446 for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--)
448 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
449 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
452 if (remain <= 1)
453 goto finally;
454 actual[0] = '~';
455 actual++;
456 remain--;
458 pos += length - width + 1;
460 /* copy suffix of text */
461 for (; pos < length && remain > 1; pos++, actual++, remain--)
463 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
464 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
467 else
469 /* copy all characters */
470 for (; pos < length && remain > 1; pos++, actual++, remain--)
472 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
473 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
477 finally:
478 actual[0] = '\0';
479 return result;
482 static int
483 str_ascii_offset_to_pos (const char *text, size_t length)
485 (void) text;
486 return (int) length;
489 static int
490 str_ascii_column_to_pos (const char *text, size_t pos)
492 (void) text;
493 return (int) pos;
496 static char *
497 str_ascii_create_search_needle (const char *needle, int case_sen)
499 (void) case_sen;
500 return (char *) needle;
503 static void
504 str_ascii_release_search_needle (char *needle, int case_sen)
506 (void) case_sen;
507 (void) needle;
511 static const char *
512 str_ascii_search_first (const char *text, const char *search, int case_sen)
514 char *fold_text;
515 char *fold_search;
516 const char *match;
517 size_t offset;
519 fold_text = (case_sen) ? (char *) text : g_ascii_strdown (text, -1);
520 fold_search = (case_sen) ? (char *) search : g_ascii_strdown (search, -1);
522 match = g_strstr_len (fold_text, -1, fold_search);
523 if (match != NULL)
525 offset = match - fold_text;
526 match = text + offset;
529 if (!case_sen)
531 g_free (fold_text);
532 g_free (fold_search);
535 return match;
538 static const char *
539 str_ascii_search_last (const char *text, const char *search, int case_sen)
541 char *fold_text;
542 char *fold_search;
543 const char *match;
544 size_t offset;
546 fold_text = (case_sen) ? (char *) text : g_ascii_strdown (text, -1);
547 fold_search = (case_sen) ? (char *) search : g_ascii_strdown (search, -1);
549 match = g_strrstr_len (fold_text, -1, fold_search);
550 if (match != NULL)
552 offset = match - fold_text;
553 match = text + offset;
556 if (!case_sen)
558 g_free (fold_text);
559 g_free (fold_search);
562 return match;
565 static int
566 str_ascii_compare (const char *t1, const char *t2)
568 return strcmp (t1, t2);
571 static int
572 str_ascii_ncompare (const char *t1, const char *t2)
574 return strncmp (t1, t2, min (strlen (t1), strlen (t2)));
577 static int
578 str_ascii_casecmp (const char *t1, const char *t2)
580 return g_ascii_strcasecmp (t1, t2);
583 static int
584 str_ascii_ncasecmp (const char *t1, const char *t2)
586 return g_ascii_strncasecmp (t1, t2, min (strlen (t1), strlen (t2)));
589 static void
590 str_ascii_fix_string (char *text)
592 for (; text[0] != '\0'; text++)
594 text[0] = ((unsigned char) text[0] < 128) ? text[0] : '?';
598 static char *
599 str_ascii_create_key (const char *text, int case_sen)
601 (void) case_sen;
602 return (char *) text;
605 static int
606 str_ascii_key_collate (const char *t1, const char *t2, int case_sen)
608 return (case_sen) ? strcmp (t1, t2) : g_ascii_strcasecmp (t1, t2);
611 static void
612 str_ascii_release_key (char *key, int case_sen)
614 (void) key;
615 (void) case_sen;
618 static int
619 str_ascii_prefix (const char *text, const char *prefix)
621 int result;
622 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
623 && text[result] == prefix[result]; result++);
624 return result;
627 static int
628 str_ascii_caseprefix (const char *text, const char *prefix)
630 int result;
631 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
632 && g_ascii_toupper (text[result]) == g_ascii_toupper (prefix[result]); result++);
633 return result;
637 struct str_class
638 str_ascii_init (void)
640 struct str_class result;
642 result.conv_gerror_message = str_ascii_conv_gerror_message;
643 result.vfs_convert_to = str_ascii_vfs_convert_to;
644 result.insert_replace_char = str_ascii_insert_replace_char;
645 result.is_valid_string = str_ascii_is_valid_string;
646 result.is_valid_char = str_ascii_is_valid_char;
647 result.cnext_char = str_ascii_cnext_char;
648 result.cprev_char = str_ascii_cprev_char;
649 result.cnext_char_safe = str_ascii_cnext_char;
650 result.cprev_char_safe = str_ascii_cprev_char;
651 result.cnext_noncomb_char = str_ascii_cnext_noncomb_char;
652 result.cprev_noncomb_char = str_ascii_cprev_noncomb_char;
653 result.isspace = str_ascii_isspace;
654 result.ispunct = str_ascii_ispunct;
655 result.isalnum = str_ascii_isalnum;
656 result.isdigit = str_ascii_isdigit;
657 result.isprint = str_ascii_isprint;
658 result.iscombiningmark = str_ascii_iscombiningmark;
659 result.toupper = str_ascii_toupper;
660 result.tolower = str_ascii_tolower;
661 result.length = str_ascii_length;
662 result.length2 = str_ascii_length2;
663 result.length_noncomb = str_ascii_length;
664 result.fix_string = str_ascii_fix_string;
665 result.term_form = str_ascii_term_form;
666 result.fit_to_term = str_ascii_fit_to_term;
667 result.term_trim = str_ascii_term_trim;
668 result.term_width2 = str_ascii_term_width2;
669 result.term_width1 = str_ascii_term_width1;
670 result.term_char_width = str_ascii_term_char_width;
671 result.term_substring = str_ascii_term_substring;
672 result.trunc = str_ascii_trunc;
673 result.offset_to_pos = str_ascii_offset_to_pos;
674 result.column_to_pos = str_ascii_column_to_pos;
675 result.create_search_needle = str_ascii_create_search_needle;
676 result.release_search_needle = str_ascii_release_search_needle;
677 result.search_first = str_ascii_search_first;
678 result.search_last = str_ascii_search_last;
679 result.compare = str_ascii_compare;
680 result.ncompare = str_ascii_ncompare;
681 result.casecmp = str_ascii_casecmp;
682 result.ncasecmp = str_ascii_ncasecmp;
683 result.prefix = str_ascii_prefix;
684 result.caseprefix = str_ascii_caseprefix;
685 result.create_key = str_ascii_create_key;
686 result.create_key_for_filename = str_ascii_create_key;
687 result.key_collate = str_ascii_key_collate;
688 result.release_key = str_ascii_release_key;
690 return result;