cppcheck: reduce variable scope.
[midnight-commander.git] / lib / strutil / strutilascii.c
blobc8946243a37a5c2b7c11bb6612642e25a4bdeea3
1 /*
2 ASCII strings utilities
4 Copyright (C) 2007, 2011, 2013
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/>.
26 #include <config.h>
28 #include <ctype.h>
29 #include <stdlib.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 than 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')
77 return 0;
79 (*text)++;
80 return 1;
83 static int
84 str_ascii_cprev_noncomb_char (const char **text, const char *begin)
86 if ((*text) == begin)
87 return 0;
89 (*text)--;
90 return 1;
93 static int
94 str_ascii_isspace (const char *text)
96 return g_ascii_isspace ((gchar) text[0]);
99 static int
100 str_ascii_ispunct (const char *text)
102 return g_ascii_ispunct ((gchar) text[0]);
105 static int
106 str_ascii_isalnum (const char *text)
108 return g_ascii_isalnum ((gchar) text[0]);
111 static int
112 str_ascii_isdigit (const char *text)
114 return g_ascii_isdigit ((gchar) text[0]);
117 static int
118 str_ascii_isprint (const char *text)
120 return g_ascii_isprint ((gchar) text[0]);
123 static gboolean
124 str_ascii_iscombiningmark (const char *text)
126 (void) text;
127 return FALSE;
130 static int
131 str_ascii_toupper (const char *text, char **out, size_t * remain)
133 if (*remain <= 1)
134 return 0;
136 (*out)[0] = (char) g_ascii_toupper ((gchar) text[0]);
137 (*out)++;
138 (*remain)--;
139 return 1;
142 static int
143 str_ascii_tolower (const char *text, char **out, size_t * remain)
145 if (*remain <= 1)
146 return 0;
148 (*out)[0] = (char) g_ascii_tolower ((gchar) text[0]);
149 (*out)++;
150 (*remain)--;
151 return 1;
154 static int
155 str_ascii_length (const char *text)
157 return strlen (text);
160 static int
161 str_ascii_length2 (const char *text, int size)
163 return (size >= 0) ? min (strlen (text), (gsize) size) : strlen (text);
166 static gchar *
167 str_ascii_conv_gerror_message (GError * error, const char *def_msg)
169 /* the same as str_utf8_conv_gerror_message() */
170 if (error != NULL)
171 return g_strdup (error->message);
173 return g_strdup (def_msg != NULL ? def_msg : "");
176 static estr_t
177 str_ascii_vfs_convert_to (GIConv coder, const char *string, int size, GString * buffer)
179 (void) coder;
180 g_string_append_len (buffer, string, size);
181 return ESTR_SUCCESS;
184 static const char *
185 str_ascii_term_form (const char *text)
187 static char result[BUF_MEDIUM];
188 char *actual;
189 size_t remain;
190 size_t length;
191 size_t pos = 0;
193 actual = result;
194 remain = sizeof (result);
195 length = strlen (text);
197 /* go throw all characters and check, if they are ascii and printable */
198 for (; pos < length && remain > 1; pos++, actual++, remain--)
200 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
201 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
204 actual[0] = '\0';
205 return result;
208 static const char *
209 str_ascii_fit_to_term (const char *text, int width, align_crt_t just_mode)
211 static char result[BUF_MEDIUM];
212 char *actual;
213 size_t remain;
214 int ident = 0;
215 size_t length;
216 size_t pos = 0;
218 length = strlen (text);
219 actual = result;
220 remain = sizeof (result);
222 if ((int) length <= width)
224 switch (HIDE_FIT (just_mode))
226 case J_CENTER_LEFT:
227 case J_CENTER:
228 ident = (width - length) / 2;
229 break;
230 case J_RIGHT:
231 ident = width - length;
232 break;
235 /* add space before text */
236 if ((int) remain <= ident)
237 goto finally;
238 memset (actual, ' ', ident);
239 actual += ident;
240 remain -= ident;
242 /* copy all characters */
243 for (; pos < (gsize) length && remain > 1; pos++, actual++, remain--)
245 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
246 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
249 /* add space after text */
250 if (width - length - ident > 0)
252 if (remain <= width - length - ident)
253 goto finally;
254 memset (actual, ' ', width - length - ident);
255 actual += width - length - ident;
258 else if (IS_FIT (just_mode))
260 /* copy prefix of text, that is not wider than width / 2 */
261 for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--)
263 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
264 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
267 if (remain <= 1)
268 goto finally;
269 actual[0] = '~';
270 actual++;
271 remain--;
273 pos += length - width + 1;
275 /* copy suffix of text */
276 for (; pos < length && remain > 1; pos++, actual++, remain--)
278 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
279 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
282 else
284 switch (HIDE_FIT (just_mode))
286 case J_CENTER:
287 ident = (length - width) / 2;
288 break;
289 case J_RIGHT:
290 ident = length - width;
291 break;
294 /* copy substring text, substring start from ident and take width
295 * characters from text */
296 pos += ident;
297 for (; pos < (gsize) (ident + width) && remain > 1; pos++, actual++, remain--)
299 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
300 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
305 finally:
306 actual[0] = '\0';
307 return result;
310 static const char *
311 str_ascii_term_trim (const char *text, int width)
313 static char result[BUF_MEDIUM];
314 size_t remain;
315 char *actual;
316 size_t length;
318 length = strlen (text);
319 actual = result;
320 remain = sizeof (result);
322 if (width > 0)
324 size_t pos;
326 if (width >= (int) length)
328 /* copy all characters */
329 for (pos = 0; pos < length && remain > 1; pos++, actual++, remain--)
331 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
332 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
335 else if (width <= 3)
337 memset (actual, '.', width);
338 actual += width;
340 else
342 memset (actual, '.', 3);
343 actual += 3;
344 remain -= 3;
346 /* copy suffix of text */
347 for (pos = length - width + 3; 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] : '.';
355 actual[0] = '\0';
356 return result;
359 static int
360 str_ascii_term_width2 (const char *text, size_t length)
362 return (length != (size_t) (-1)) ? min (strlen (text), length) : strlen (text);
365 static int
366 str_ascii_term_width1 (const char *text)
368 return str_ascii_term_width2 (text, (size_t) (-1));
371 static int
372 str_ascii_term_char_width (const char *text)
374 (void) text;
375 return 1;
378 static const char *
379 str_ascii_term_substring (const char *text, int start, int width)
381 static char result[BUF_MEDIUM];
382 size_t remain;
383 char *actual;
384 size_t length;
386 actual = result;
387 remain = sizeof (result);
388 length = strlen (text);
390 if (start < (int) length)
392 size_t pos;
394 /* copy at most width characters from text from start */
395 for (pos = start; pos < length && width > 0 && remain > 1;
396 pos++, width--, actual++, remain--)
398 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
399 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
403 /* if text is shorter then width, add space to the end */
404 for (; width > 0 && remain > 1; actual++, remain--, width--)
405 actual[0] = ' ';
407 actual[0] = '\0';
408 return result;
411 static const char *
412 str_ascii_trunc (const char *text, int width)
414 static char result[MC_MAXPATHLEN];
415 int remain;
416 char *actual;
417 size_t pos = 0;
418 size_t length;
420 actual = result;
421 remain = sizeof (result);
422 length = strlen (text);
424 if ((int) length > width)
426 /* copy prefix of text */
427 for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--)
429 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
430 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
433 if (remain <= 1)
434 goto finally;
435 actual[0] = '~';
436 actual++;
437 remain--;
439 pos += length - width + 1;
441 /* copy suffix of text */
442 for (; pos < length && remain > 1; pos++, actual++, remain--)
444 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
445 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
448 else
450 /* copy all characters */
451 for (; pos < length && remain > 1; pos++, actual++, remain--)
453 actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
454 actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
458 finally:
459 actual[0] = '\0';
460 return result;
463 static int
464 str_ascii_offset_to_pos (const char *text, size_t length)
466 (void) text;
467 return (int) length;
470 static int
471 str_ascii_column_to_pos (const char *text, size_t pos)
473 (void) text;
474 return (int) pos;
477 static char *
478 str_ascii_create_search_needle (const char *needle, int case_sen)
480 (void) case_sen;
481 return (char *) needle;
484 static void
485 str_ascii_release_search_needle (char *needle, int case_sen)
487 (void) case_sen;
488 (void) needle;
492 static const char *
493 str_ascii_search_first (const char *text, const char *search, int case_sen)
495 char *fold_text;
496 char *fold_search;
497 const char *match;
499 fold_text = (case_sen) ? (char *) text : g_ascii_strdown (text, -1);
500 fold_search = (case_sen) ? (char *) search : g_ascii_strdown (search, -1);
502 match = g_strstr_len (fold_text, -1, fold_search);
503 if (match != NULL)
505 size_t offset;
507 offset = match - fold_text;
508 match = text + offset;
511 if (!case_sen)
513 g_free (fold_text);
514 g_free (fold_search);
517 return match;
520 static const char *
521 str_ascii_search_last (const char *text, const char *search, int case_sen)
523 char *fold_text;
524 char *fold_search;
525 const char *match;
527 fold_text = (case_sen) ? (char *) text : g_ascii_strdown (text, -1);
528 fold_search = (case_sen) ? (char *) search : g_ascii_strdown (search, -1);
530 match = g_strrstr_len (fold_text, -1, fold_search);
531 if (match != NULL)
533 size_t offset;
535 offset = match - fold_text;
536 match = text + offset;
539 if (!case_sen)
541 g_free (fold_text);
542 g_free (fold_search);
545 return match;
548 static int
549 str_ascii_compare (const char *t1, const char *t2)
551 return strcmp (t1, t2);
554 static int
555 str_ascii_ncompare (const char *t1, const char *t2)
557 return strncmp (t1, t2, min (strlen (t1), strlen (t2)));
560 static int
561 str_ascii_casecmp (const char *t1, const char *t2)
563 return g_ascii_strcasecmp (t1, t2);
566 static int
567 str_ascii_ncasecmp (const char *t1, const char *t2)
569 return g_ascii_strncasecmp (t1, t2, min (strlen (t1), strlen (t2)));
572 static void
573 str_ascii_fix_string (char *text)
575 for (; text[0] != '\0'; text++)
576 text[0] = ((unsigned char) text[0] < 128) ? text[0] : '?';
579 static char *
580 str_ascii_create_key (const char *text, int case_sen)
582 (void) case_sen;
583 return (char *) text;
586 static int
587 str_ascii_key_collate (const char *t1, const char *t2, int case_sen)
589 return (case_sen) ? strcmp (t1, t2) : g_ascii_strcasecmp (t1, t2);
592 static void
593 str_ascii_release_key (char *key, int case_sen)
595 (void) key;
596 (void) case_sen;
599 static int
600 str_ascii_prefix (const char *text, const char *prefix)
602 int result;
604 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
605 && text[result] == prefix[result]; result++);
607 return result;
610 static int
611 str_ascii_caseprefix (const char *text, const char *prefix)
613 int result;
615 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
616 && g_ascii_toupper (text[result]) == g_ascii_toupper (prefix[result]); result++);
618 return result;
621 struct str_class
622 str_ascii_init (void)
624 struct str_class result;
626 result.conv_gerror_message = str_ascii_conv_gerror_message;
627 result.vfs_convert_to = str_ascii_vfs_convert_to;
628 result.insert_replace_char = str_ascii_insert_replace_char;
629 result.is_valid_string = str_ascii_is_valid_string;
630 result.is_valid_char = str_ascii_is_valid_char;
631 result.cnext_char = str_ascii_cnext_char;
632 result.cprev_char = str_ascii_cprev_char;
633 result.cnext_char_safe = str_ascii_cnext_char;
634 result.cprev_char_safe = str_ascii_cprev_char;
635 result.cnext_noncomb_char = str_ascii_cnext_noncomb_char;
636 result.cprev_noncomb_char = str_ascii_cprev_noncomb_char;
637 result.char_isspace = str_ascii_isspace;
638 result.char_ispunct = str_ascii_ispunct;
639 result.char_isalnum = str_ascii_isalnum;
640 result.char_isdigit = str_ascii_isdigit;
641 result.char_isprint = str_ascii_isprint;
642 result.char_iscombiningmark = str_ascii_iscombiningmark;
643 result.char_toupper = str_ascii_toupper;
644 result.char_tolower = str_ascii_tolower;
645 result.length = str_ascii_length;
646 result.length2 = str_ascii_length2;
647 result.length_noncomb = str_ascii_length;
648 result.fix_string = str_ascii_fix_string;
649 result.term_form = str_ascii_term_form;
650 result.fit_to_term = str_ascii_fit_to_term;
651 result.term_trim = str_ascii_term_trim;
652 result.term_width2 = str_ascii_term_width2;
653 result.term_width1 = str_ascii_term_width1;
654 result.term_char_width = str_ascii_term_char_width;
655 result.term_substring = str_ascii_term_substring;
656 result.trunc = str_ascii_trunc;
657 result.offset_to_pos = str_ascii_offset_to_pos;
658 result.column_to_pos = str_ascii_column_to_pos;
659 result.create_search_needle = str_ascii_create_search_needle;
660 result.release_search_needle = str_ascii_release_search_needle;
661 result.search_first = str_ascii_search_first;
662 result.search_last = str_ascii_search_last;
663 result.compare = str_ascii_compare;
664 result.ncompare = str_ascii_ncompare;
665 result.casecmp = str_ascii_casecmp;
666 result.ncasecmp = str_ascii_ncasecmp;
667 result.prefix = str_ascii_prefix;
668 result.caseprefix = str_ascii_caseprefix;
669 result.create_key = str_ascii_create_key;
670 result.create_key_for_filename = str_ascii_create_key;
671 result.key_collate = str_ascii_key_collate;
672 result.release_key = str_ascii_release_key;
674 return result;