123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- /*
- Functions for escaping and unescaping strings
- Copyright (C) 2009-2024
- 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/strutil.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 *
- str_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 *
- str_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 *
- str_shell_escape (const char *src)
- {
- return str_escape (src, -1, ESCAPE_SHELL_CHARS, FALSE);
- }
- /* --------------------------------------------------------------------------------------------- */
- char *
- str_glob_escape (const char *src)
- {
- return str_escape (src, -1, ESCAPE_GLOB_CHARS, TRUE);
- }
- /* --------------------------------------------------------------------------------------------- */
- char *
- str_regex_escape (const char *src)
- {
- return str_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 *
- str_shell_unescape (const char *text)
- {
- return str_unescape (text, -1, ESCAPE_SHELL_CHARS, TRUE);
- }
- /* --------------------------------------------------------------------------------------------- */
- char *
- str_glob_unescape (const char *text)
- {
- return str_unescape (text, -1, ESCAPE_GLOB_CHARS, TRUE);
- }
- /* --------------------------------------------------------------------------------------------- */
- char *
- str_regex_unescape (const char *text)
- {
- return str_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
- str_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;
- }
- /* --------------------------------------------------------------------------------------------- */
|