diff options
Diffstat (limited to 'lib/strutil/strutilascii.c')
-rw-r--r-- | lib/strutil/strutilascii.c | 785 |
1 files changed, 785 insertions, 0 deletions
diff --git a/lib/strutil/strutilascii.c b/lib/strutil/strutilascii.c new file mode 100644 index 0000000..421bfdb --- /dev/null +++ b/lib/strutil/strutilascii.c @@ -0,0 +1,785 @@ +/* + ASCII strings utilities + + Copyright (C) 2007-2023 + Free Software Foundation, Inc. + + Written by: + Rostislav Benes, 2007 + + This file is part of the Midnight Commander. + + The Midnight Commander is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + The Midnight Commander is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <ctype.h> +#include <stdlib.h> + +#include "lib/global.h" +#include "lib/strutil.h" + +/* using g_ascii function from glib + * on terminal are showed only ascii characters (lower than 0x80) + */ + +/*** global variables ****************************************************************************/ + +/*** file scope macro definitions ****************************************************************/ + +/*** file scope type declarations ****************************************************************/ + +/*** forward declarations (file scope functions) *************************************************/ + +/*** file scope variables ************************************************************************/ + +static const char replch = '?'; + +/* --------------------------------------------------------------------------------------------- */ +/*** file scope functions ************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +static void +str_ascii_insert_replace_char (GString * buffer) +{ + g_string_append_c (buffer, replch); +} + +/* --------------------------------------------------------------------------------------------- */ + +static gboolean +str_ascii_is_valid_string (const char *text) +{ + (void) text; + return TRUE; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_is_valid_char (const char *ch, size_t size) +{ + (void) ch; + (void) size; + return 1; +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +str_ascii_cnext_char (const char **text) +{ + (*text)++; +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +str_ascii_cprev_char (const char **text) +{ + (*text)--; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_cnext_noncomb_char (const char **text) +{ + if (*text[0] == '\0') + return 0; + + (*text)++; + return 1; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_cprev_noncomb_char (const char **text, const char *begin) +{ + if ((*text) == begin) + return 0; + + (*text)--; + return 1; +} + +/* --------------------------------------------------------------------------------------------- */ + +static gboolean +str_ascii_isspace (const char *text) +{ + return g_ascii_isspace ((gchar) text[0]); +} + +/* --------------------------------------------------------------------------------------------- */ + +static gboolean +str_ascii_ispunct (const char *text) +{ + return g_ascii_ispunct ((gchar) text[0]); +} + +/* --------------------------------------------------------------------------------------------- */ + +static gboolean +str_ascii_isalnum (const char *text) +{ + return g_ascii_isalnum ((gchar) text[0]); +} + +/* --------------------------------------------------------------------------------------------- */ + +static gboolean +str_ascii_isdigit (const char *text) +{ + return g_ascii_isdigit ((gchar) text[0]); +} + +/* --------------------------------------------------------------------------------------------- */ + +static gboolean +str_ascii_isprint (const char *text) +{ + return g_ascii_isprint ((gchar) text[0]); +} + +/* --------------------------------------------------------------------------------------------- */ + +static gboolean +str_ascii_iscombiningmark (const char *text) +{ + (void) text; + return FALSE; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_toupper (const char *text, char **out, size_t * remain) +{ + if (*remain <= 1) + return FALSE; + + (*out)[0] = (char) g_ascii_toupper ((gchar) text[0]); + (*out)++; + (*remain)--; + return TRUE; +} + +/* --------------------------------------------------------------------------------------------- */ + +static gboolean +str_ascii_tolower (const char *text, char **out, size_t * remain) +{ + if (*remain <= 1) + return FALSE; + + (*out)[0] = (char) g_ascii_tolower ((gchar) text[0]); + (*out)++; + (*remain)--; + return TRUE; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_length (const char *text) +{ + return strlen (text); +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_length2 (const char *text, int size) +{ + return (size >= 0) ? MIN (strlen (text), (gsize) size) : strlen (text); +} + +/* --------------------------------------------------------------------------------------------- */ + +static gchar * +str_ascii_conv_gerror_message (GError * mcerror, const char *def_msg) +{ + /* the same as str_utf8_conv_gerror_message() */ + if (mcerror != NULL) + return g_strdup (mcerror->message); + + return g_strdup (def_msg != NULL ? def_msg : ""); +} + +/* --------------------------------------------------------------------------------------------- */ + +static estr_t +str_ascii_vfs_convert_to (GIConv coder, const char *string, int size, GString * buffer) +{ + (void) coder; + g_string_append_len (buffer, string, size); + return ESTR_SUCCESS; +} + +/* --------------------------------------------------------------------------------------------- */ + +static const char * +str_ascii_term_form (const char *text) +{ + static char result[BUF_MEDIUM]; + char *actual; + size_t remain; + size_t length; + size_t pos = 0; + + actual = result; + remain = sizeof (result); + length = strlen (text); + + /* go throw all characters and check, if they are ascii and printable */ + for (; pos < length && remain > 1; pos++, actual++, remain--) + { + actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?'; + actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.'; + } + + actual[0] = '\0'; + return result; +} + +/* --------------------------------------------------------------------------------------------- */ + +static const char * +str_ascii_fit_to_term (const char *text, int width, align_crt_t just_mode) +{ + static char result[BUF_MEDIUM]; + char *actual; + size_t remain; + int ident = 0; + size_t length; + size_t pos = 0; + + length = strlen (text); + actual = result; + remain = sizeof (result); + + if ((int) length <= width) + { + switch (HIDE_FIT (just_mode)) + { + case J_CENTER_LEFT: + case J_CENTER: + ident = (width - length) / 2; + break; + case J_RIGHT: + ident = width - length; + break; + default: + break; + } + + /* add space before text */ + if ((int) remain <= ident) + goto finally; + memset (actual, ' ', ident); + actual += ident; + remain -= ident; + + /* copy all characters */ + for (; pos < (gsize) length && remain > 1; pos++, actual++, remain--) + { + actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?'; + actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.'; + } + + /* add space after text */ + if (width - length - ident > 0) + { + if (remain <= width - length - ident) + goto finally; + memset (actual, ' ', width - length - ident); + actual += width - length - ident; + } + } + else if (IS_FIT (just_mode)) + { + /* copy prefix of text, that is not wider than width / 2 */ + for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--) + { + actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?'; + actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.'; + } + + if (remain <= 1) + goto finally; + actual[0] = '~'; + actual++; + remain--; + + pos += length - width + 1; + + /* copy suffix of text */ + for (; pos < length && remain > 1; pos++, actual++, remain--) + { + actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?'; + actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.'; + } + } + else + { + switch (HIDE_FIT (just_mode)) + { + case J_CENTER: + ident = (length - width) / 2; + break; + case J_RIGHT: + ident = length - width; + break; + default: + break; + } + + /* copy substring text, substring start from ident and take width + * characters from text */ + pos += ident; + for (; pos < (gsize) (ident + width) && remain > 1; pos++, actual++, remain--) + { + actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?'; + actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.'; + } + + } + + finally: + if (actual >= result + sizeof (result)) + actual = result + sizeof (result) - 1; + actual[0] = '\0'; + return result; +} + +/* --------------------------------------------------------------------------------------------- */ + +static const char * +str_ascii_term_trim (const char *text, int width) +{ + static char result[BUF_MEDIUM]; + size_t remain; + char *actual; + size_t length; + + length = strlen (text); + actual = result; + remain = sizeof (result); + + if (width > 0) + { + size_t pos; + + if (width >= (int) length) + { + /* copy all characters */ + for (pos = 0; pos < length && remain > 1; pos++, actual++, remain--) + { + actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?'; + actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.'; + } + } + else if (width <= 3) + { + memset (actual, '.', width); + actual += width; + } + else + { + memset (actual, '.', 3); + actual += 3; + remain -= 3; + + /* copy suffix of text */ + for (pos = length - width + 3; pos < length && remain > 1; pos++, actual++, remain--) + { + actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?'; + actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.'; + } + } + } + + actual[0] = '\0'; + return result; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_term_width2 (const char *text, size_t length) +{ + return (length != (size_t) (-1)) ? MIN (strlen (text), length) : strlen (text); +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_term_width1 (const char *text) +{ + return str_ascii_term_width2 (text, (size_t) (-1)); +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_term_char_width (const char *text) +{ + (void) text; + return 1; +} + +/* --------------------------------------------------------------------------------------------- */ + +static const char * +str_ascii_term_substring (const char *text, int start, int width) +{ + static char result[BUF_MEDIUM]; + size_t remain; + char *actual; + size_t length; + + actual = result; + remain = sizeof (result); + length = strlen (text); + + if (start < (int) length) + { + size_t pos; + + /* copy at most width characters from text from start */ + for (pos = start; pos < length && width > 0 && remain > 1; + pos++, width--, actual++, remain--) + { + actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?'; + actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.'; + } + } + + /* if text is shorter then width, add space to the end */ + for (; width > 0 && remain > 1; actual++, remain--, width--) + actual[0] = ' '; + + actual[0] = '\0'; + return result; +} + +/* --------------------------------------------------------------------------------------------- */ + +static const char * +str_ascii_trunc (const char *text, int width) +{ + static char result[MC_MAXPATHLEN]; + int remain; + char *actual; + size_t pos = 0; + size_t length; + + actual = result; + remain = sizeof (result); + length = strlen (text); + + if ((int) length > width) + { + /* copy prefix of text */ + for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--) + { + actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?'; + actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.'; + } + + if (remain <= 1) + goto finally; + actual[0] = '~'; + actual++; + remain--; + + pos += length - width + 1; + + /* copy suffix of text */ + for (; pos < length && remain > 1; pos++, actual++, remain--) + { + actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?'; + actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.'; + } + } + else + { + /* copy all characters */ + for (; pos < length && remain > 1; pos++, actual++, remain--) + { + actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?'; + actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.'; + } + } + + finally: + actual[0] = '\0'; + return result; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_offset_to_pos (const char *text, size_t length) +{ + (void) text; + return (int) length; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_column_to_pos (const char *text, size_t pos) +{ + (void) text; + return (int) pos; +} + +/* --------------------------------------------------------------------------------------------- */ + +static char * +str_ascii_create_search_needle (const char *needle, gboolean case_sen) +{ + (void) case_sen; + return (char *) needle; +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +str_ascii_release_search_needle (char *needle, gboolean case_sen) +{ + (void) case_sen; + (void) needle; + +} + +/* --------------------------------------------------------------------------------------------- */ + +static const char * +str_ascii_search_first (const char *text, const char *search, gboolean case_sen) +{ + char *fold_text; + char *fold_search; + const char *match; + + fold_text = case_sen ? (char *) text : g_ascii_strdown (text, -1); + fold_search = case_sen ? (char *) search : g_ascii_strdown (search, -1); + + match = g_strstr_len (fold_text, -1, fold_search); + if (match != NULL) + { + size_t offset; + + offset = match - fold_text; + match = text + offset; + } + + if (!case_sen) + { + g_free (fold_text); + g_free (fold_search); + } + + return match; +} + +/* --------------------------------------------------------------------------------------------- */ + +static const char * +str_ascii_search_last (const char *text, const char *search, gboolean case_sen) +{ + char *fold_text; + char *fold_search; + const char *match; + + fold_text = case_sen ? (char *) text : g_ascii_strdown (text, -1); + fold_search = case_sen ? (char *) search : g_ascii_strdown (search, -1); + + match = g_strrstr_len (fold_text, -1, fold_search); + if (match != NULL) + { + size_t offset; + + offset = match - fold_text; + match = text + offset; + } + + if (!case_sen) + { + g_free (fold_text); + g_free (fold_search); + } + + return match; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_compare (const char *t1, const char *t2) +{ + return strcmp (t1, t2); +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_ncompare (const char *t1, const char *t2) +{ + return strncmp (t1, t2, MIN (strlen (t1), strlen (t2))); +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_casecmp (const char *t1, const char *t2) +{ + return g_ascii_strcasecmp (t1, t2); +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_ncasecmp (const char *t1, const char *t2) +{ + return g_ascii_strncasecmp (t1, t2, MIN (strlen (t1), strlen (t2))); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +str_ascii_fix_string (char *text) +{ + for (; text[0] != '\0'; text++) + text[0] = ((unsigned char) text[0] < 128) ? text[0] : '?'; +} + +/* --------------------------------------------------------------------------------------------- */ + +static char * +str_ascii_create_key (const char *text, gboolean case_sen) +{ + (void) case_sen; + return (char *) text; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_key_collate (const char *t1, const char *t2, gboolean case_sen) +{ + return case_sen ? strcmp (t1, t2) : g_ascii_strcasecmp (t1, t2); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +str_ascii_release_key (char *key, gboolean case_sen) +{ + (void) key; + (void) case_sen; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_prefix (const char *text, const char *prefix) +{ + int result; + + for (result = 0; text[result] != '\0' && prefix[result] != '\0' + && text[result] == prefix[result]; result++); + + return result; +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +str_ascii_caseprefix (const char *text, const char *prefix) +{ + int result; + + for (result = 0; text[result] != '\0' && prefix[result] != '\0' + && g_ascii_toupper (text[result]) == g_ascii_toupper (prefix[result]); result++); + + return result; +} + +/* --------------------------------------------------------------------------------------------- */ +/*** public functions ****************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +struct str_class +str_ascii_init (void) +{ + struct str_class result; + + result.conv_gerror_message = str_ascii_conv_gerror_message; + result.vfs_convert_to = str_ascii_vfs_convert_to; + result.insert_replace_char = str_ascii_insert_replace_char; + result.is_valid_string = str_ascii_is_valid_string; + result.is_valid_char = str_ascii_is_valid_char; + result.cnext_char = str_ascii_cnext_char; + result.cprev_char = str_ascii_cprev_char; + result.cnext_char_safe = str_ascii_cnext_char; + result.cprev_char_safe = str_ascii_cprev_char; + result.cnext_noncomb_char = str_ascii_cnext_noncomb_char; + result.cprev_noncomb_char = str_ascii_cprev_noncomb_char; + result.char_isspace = str_ascii_isspace; + result.char_ispunct = str_ascii_ispunct; + result.char_isalnum = str_ascii_isalnum; + result.char_isdigit = str_ascii_isdigit; + result.char_isprint = str_ascii_isprint; + result.char_iscombiningmark = str_ascii_iscombiningmark; + result.char_toupper = str_ascii_toupper; + result.char_tolower = str_ascii_tolower; + result.length = str_ascii_length; + result.length2 = str_ascii_length2; + result.length_noncomb = str_ascii_length; + result.fix_string = str_ascii_fix_string; + result.term_form = str_ascii_term_form; + result.fit_to_term = str_ascii_fit_to_term; + result.term_trim = str_ascii_term_trim; + result.term_width2 = str_ascii_term_width2; + result.term_width1 = str_ascii_term_width1; + result.term_char_width = str_ascii_term_char_width; + result.term_substring = str_ascii_term_substring; + result.trunc = str_ascii_trunc; + result.offset_to_pos = str_ascii_offset_to_pos; + result.column_to_pos = str_ascii_column_to_pos; + result.create_search_needle = str_ascii_create_search_needle; + result.release_search_needle = str_ascii_release_search_needle; + result.search_first = str_ascii_search_first; + result.search_last = str_ascii_search_last; + result.compare = str_ascii_compare; + result.ncompare = str_ascii_ncompare; + result.casecmp = str_ascii_casecmp; + result.ncasecmp = str_ascii_ncasecmp; + result.prefix = str_ascii_prefix; + result.caseprefix = str_ascii_caseprefix; + result.create_key = str_ascii_create_key; + result.create_key_for_filename = str_ascii_create_key; + result.key_collate = str_ascii_key_collate; + result.release_key = str_ascii_release_key; + + return result; +} + +/* --------------------------------------------------------------------------------------------- */ |