Merge branch '2791_path_encoding' into 4.8.1-stable
[midnight-commander.git] / lib / strutil / strescape.c
blobe99191c941e11865a6f174e4a64f8d9a355fd8cd
1 /*
2 Functions for escaping and unescaping strings
4 Copyright (C) 2009, 2011
5 The Free Software Foundation, Inc.
7 Written by:
8 Slava Zanko <slavazanko@gmail.com>, 2009;
9 Patrick Winnertz <winnie@debian.org>, 2009
11 This file is part of the Midnight Commander.
13 The Midnight Commander is free software: you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation, either version 3 of the License,
16 or (at your option) any later version.
18 The Midnight Commander is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <config.h>
29 #include "lib/strescape.h"
31 /*** global variables ****************************************************************************/
33 /*** file scope macro definitions ****************************************************************/
35 /*** file scope type declarations ****************************************************************/
37 /*** file scope variables ************************************************************************/
39 static const char ESCAPE_SHELL_CHARS[] = " !#$%()&{}[]`?|<>;*\\\"'";
40 static const char ESCAPE_REGEX_CHARS[] = "^!#$%()&{}[]`?|<>;*.\\";
41 static const char ESCAPE_GLOB_CHARS[] = "$*\\?";
43 /*** file scope functions ************************************************************************/
45 /*** public functions ****************************************************************************/
47 char *
48 strutils_escape (const char *src, gsize src_len, const char *escaped_chars,
49 gboolean escape_non_printable)
51 GString *ret;
52 gsize curr_index;
53 /* do NOT break allocation semantics */
54 if (src == NULL)
55 return NULL;
57 if (*src == '\0')
58 return strdup ("");
60 ret = g_string_new ("");
62 if (src_len == (gsize) - 1)
63 src_len = strlen (src);
65 for (curr_index = 0; curr_index < src_len; curr_index++)
67 if (escape_non_printable)
69 switch (src[curr_index])
71 case '\n':
72 g_string_append (ret, "\\n");
73 continue;
74 case '\t':
75 g_string_append (ret, "\\t");
76 continue;
77 case '\b':
78 g_string_append (ret, "\\b");
79 continue;
80 case '\0':
81 g_string_append (ret, "\\0");
82 continue;
86 if (strchr (escaped_chars, (int) src[curr_index]))
87 g_string_append_c (ret, '\\');
89 g_string_append_c (ret, src[curr_index]);
91 return g_string_free (ret, FALSE);
94 /* --------------------------------------------------------------------------------------------- */
95 char *
96 strutils_unescape (const char *src, gsize src_len, const char *unescaped_chars,
97 gboolean unescape_non_printable)
99 GString *ret;
100 gsize curr_index;
102 if (src == NULL)
103 return NULL;
105 if (*src == '\0')
106 return strdup ("");
108 ret = g_string_sized_new (16);
110 if (src_len == (gsize) (-1))
111 src_len = strlen (src);
112 src_len--;
114 for (curr_index = 0; curr_index < src_len; curr_index++)
116 if (src[curr_index] != '\\')
118 g_string_append_c (ret, src[curr_index]);
119 continue;
122 curr_index++;
124 if (unescaped_chars == ESCAPE_SHELL_CHARS && src[curr_index] == '$')
126 /* special case: \$ is used to disallow variable substitution */
127 g_string_append_c (ret, '\\');
129 else
131 if (unescape_non_printable)
133 switch (src[curr_index])
135 case 'n':
136 g_string_append_c (ret, '\n');
137 continue;
138 case 't':
139 g_string_append_c (ret, '\t');
140 continue;
141 case 'b':
142 g_string_append_c (ret, '\b');
143 continue;
144 case '0':
145 g_string_append_c (ret, '\0');
146 continue;
150 if (strchr (unescaped_chars, (int) src[curr_index]) == NULL)
151 g_string_append_c (ret, '\\');
154 g_string_append_c (ret, src[curr_index]);
156 g_string_append_c (ret, src[curr_index]);
158 return g_string_free (ret, FALSE);
161 /* --------------------------------------------------------------------------------------------- */
163 /** To be compatible with the general posix command lines we have to escape
164 strings for the command line
166 \param src
167 string for escaping
169 \returns
170 return escaped string (which needs to be freed later)
171 or NULL when NULL string is passed.
173 char *
174 strutils_shell_escape (const char *src)
176 return strutils_escape (src, -1, ESCAPE_SHELL_CHARS, FALSE);
179 /* --------------------------------------------------------------------------------------------- */
181 char *
182 strutils_glob_escape (const char *src)
184 return strutils_escape (src, -1, ESCAPE_GLOB_CHARS, TRUE);
187 /* --------------------------------------------------------------------------------------------- */
189 char *
190 strutils_regex_escape (const char *src)
192 return strutils_escape (src, -1, ESCAPE_REGEX_CHARS, TRUE);
195 /* --------------------------------------------------------------------------------------------- */
197 /** Unescape paths or other strings for e.g the internal cd
198 shell-unescape within a given buffer (writing to it!)
200 \param text
201 string for unescaping
203 \returns
204 return unescaped string (which needs to be freed)
206 char *
207 strutils_shell_unescape (const char *text)
209 return strutils_unescape (text, -1, ESCAPE_SHELL_CHARS, TRUE);
212 /* --------------------------------------------------------------------------------------------- */
214 char *
215 strutils_glob_unescape (const char *text)
217 return strutils_unescape (text, -1, ESCAPE_GLOB_CHARS, TRUE);
220 /* --------------------------------------------------------------------------------------------- */
221 char *
222 strutils_regex_unescape (const char *text)
224 return strutils_unescape (text, -1, ESCAPE_REGEX_CHARS, TRUE);
227 /* --------------------------------------------------------------------------------------------- */
229 /** Check if char in pointer contain escape'd chars
231 \param start
232 string for checking
234 \param current
235 pointer to checked character
237 \returns
238 return TRUE if string contain escaped chars
239 otherwise return FALSE
241 gboolean
242 strutils_is_char_escaped (const char *start, const char *current)
244 int num_esc = 0;
246 if (start == NULL || current == NULL || current <= start)
247 return FALSE;
249 current--;
250 while (current >= start && *current == '\\')
252 num_esc++;
253 current--;
255 return (gboolean) num_esc % 2;
258 /* --------------------------------------------------------------------------------------------- */