mc/lib/strutil/strutilascii.c
Andrew Borodin 7257f794d2 Update template for .c files.
Add section for forward declarations of local functions. This section is
located before file scope variables because functions can be used in
strucutres (see find.c for example):

/*** forward declarations (file scope functions) *************************************************/

/* button callbacks */
static int start_stop (WButton * button, int action);
static int find_do_view_file (WButton * button, int action);
static int find_do_edit_file (WButton * button, int action);

/*** file scope variables ************************************************************************/

static struct
{
    ...
    bcback_fn callback;
} fbuts[] =
{
    ...
    { B_STOP, NORMAL_BUTTON, N_("S&uspend"), 0, 0, NULL, start_stop },
    ...
    { B_VIEW, NORMAL_BUTTON, N_("&View - F3"), 0, 0, NULL, find_do_view_file },
    { B_VIEW, NORMAL_BUTTON, N_("&Edit - F4"), 0, 0, NULL, find_do_edit_file }
};

Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
2023-03-19 20:34:24 +03:00

786 lines
22 KiB
C

/*
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;
}
/* --------------------------------------------------------------------------------------------- */