diff options
Diffstat (limited to 'lib/strutil/strescape.c')
-rw-r--r-- | lib/strutil/strescape.c | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/lib/strutil/strescape.c b/lib/strutil/strescape.c new file mode 100644 index 0000000..a605ad8 --- /dev/null +++ b/lib/strutil/strescape.c @@ -0,0 +1,266 @@ +/* + Functions for escaping and unescaping strings + + Copyright (C) 2009-2023 + Free Software Foundation, Inc. + + Written by: + Slava Zanko <slavazanko@gmail.com>, 2009; + Patrick Winnertz <winnie@debian.org>, 2009 + + 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 "lib/global.h" +#include "lib/strescape.h" + +/*** global variables ****************************************************************************/ + +/*** file scope macro definitions ****************************************************************/ + +/*** file scope type declarations ****************************************************************/ + +/*** forward declarations (file scope functions) *************************************************/ + +/*** file scope variables ************************************************************************/ + +static const char ESCAPE_SHELL_CHARS[] = " !#$%()&{}[]`?|<>;*\\\"'"; +static const char ESCAPE_REGEX_CHARS[] = "^!#$%()&{}[]`?|<>;*+.\\"; +static const char ESCAPE_GLOB_CHARS[] = "$*\\?"; + +/* --------------------------------------------------------------------------------------------- */ +/*** file scope functions ************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------------------------------------- */ +/*** public functions ****************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +char * +strutils_escape (const char *src, gsize src_len, const char *escaped_chars, + gboolean escape_non_printable) +{ + GString *ret; + gsize curr_index; + /* do NOT break allocation semantics */ + if (src == NULL) + return NULL; + + if (*src == '\0') + return strdup (""); + + ret = g_string_new (""); + + if (src_len == (gsize) (-1)) + src_len = strlen (src); + + for (curr_index = 0; curr_index < src_len; curr_index++) + { + if (escape_non_printable) + { + switch (src[curr_index]) + { + case '\n': + g_string_append (ret, "\\n"); + continue; + case '\t': + g_string_append (ret, "\\t"); + continue; + case '\b': + g_string_append (ret, "\\b"); + continue; + case '\0': + g_string_append (ret, "\\0"); + continue; + default: + break; + } + } + + if (strchr (escaped_chars, (int) src[curr_index])) + g_string_append_c (ret, '\\'); + + g_string_append_c (ret, src[curr_index]); + } + return g_string_free (ret, FALSE); +} + +/* --------------------------------------------------------------------------------------------- */ + +char * +strutils_unescape (const char *src, gsize src_len, const char *unescaped_chars, + gboolean unescape_non_printable) +{ + GString *ret; + gsize curr_index; + + if (src == NULL) + return NULL; + + if (*src == '\0') + return strdup (""); + + ret = g_string_sized_new (16); + + if (src_len == (gsize) (-1)) + src_len = strlen (src); + src_len--; + + for (curr_index = 0; curr_index < src_len; curr_index++) + { + if (src[curr_index] != '\\') + { + g_string_append_c (ret, src[curr_index]); + continue; + } + + curr_index++; + + if (unescaped_chars == ESCAPE_SHELL_CHARS && src[curr_index] == '$') + { + /* special case: \$ is used to disallow variable substitution */ + g_string_append_c (ret, '\\'); + } + else + { + if (unescape_non_printable) + { + switch (src[curr_index]) + { + case 'n': + g_string_append_c (ret, '\n'); + continue; + case 't': + g_string_append_c (ret, '\t'); + continue; + case 'b': + g_string_append_c (ret, '\b'); + continue; + case '0': + g_string_append_c (ret, '\0'); + continue; + default: + break; + } + } + + if (strchr (unescaped_chars, (int) src[curr_index]) == NULL) + g_string_append_c (ret, '\\'); + } + + g_string_append_c (ret, src[curr_index]); + } + g_string_append_c (ret, src[curr_index]); + + return g_string_free (ret, FALSE); +} + +/* --------------------------------------------------------------------------------------------- */ + +/** + * To be compatible with the general posix command lines we have to escape + * strings for the command line + * + * @param src string for escaping + * + * @return escaped string (which needs to be freed later) or NULL when NULL string is passed. + */ + +char * +strutils_shell_escape (const char *src) +{ + return strutils_escape (src, -1, ESCAPE_SHELL_CHARS, FALSE); +} + +/* --------------------------------------------------------------------------------------------- */ + +char * +strutils_glob_escape (const char *src) +{ + return strutils_escape (src, -1, ESCAPE_GLOB_CHARS, TRUE); +} + +/* --------------------------------------------------------------------------------------------- */ + +char * +strutils_regex_escape (const char *src) +{ + return strutils_escape (src, -1, ESCAPE_REGEX_CHARS, TRUE); +} + +/* --------------------------------------------------------------------------------------------- */ + +/** + * Unescape paths or other strings for e.g the internal cd + * shell-unescape within a given buffer (writing to it!) + * + * @param text string for unescaping + * + * @return unescaped string (which needs to be freed) + */ + +char * +strutils_shell_unescape (const char *text) +{ + return strutils_unescape (text, -1, ESCAPE_SHELL_CHARS, TRUE); +} + +/* --------------------------------------------------------------------------------------------- */ + +char * +strutils_glob_unescape (const char *text) +{ + return strutils_unescape (text, -1, ESCAPE_GLOB_CHARS, TRUE); +} + +/* --------------------------------------------------------------------------------------------- */ +char * +strutils_regex_unescape (const char *text) +{ + return strutils_unescape (text, -1, ESCAPE_REGEX_CHARS, TRUE); +} + +/* --------------------------------------------------------------------------------------------- */ + +/** + * Check if char in pointer contain escape'd chars + * + * @param start string for checking + * @param current pointer to checked character + * + * @return TRUE if string contain escaped chars otherwise return FALSE + */ + +gboolean +strutils_is_char_escaped (const char *start, const char *current) +{ + int num_esc = 0; + + if (start == NULL || current == NULL || current <= start) + return FALSE; + + current--; + while (current >= start && *current == '\\') + { + num_esc++; + current--; + } + return (gboolean) num_esc % 2; +} + +/* --------------------------------------------------------------------------------------------- */ |