Reworked functions strutils_shell_escape and strutils_shell_unescape

also added function:
 * strutils_glob_escape
 * strutils_glob_unescape
 * strutils_regex_escape
 * strutils_regex_unescape

Signed-off-by: Slava Zanko <slavazanko@gmail.com>
This commit is contained in:
Slava Zanko 2009-06-09 15:14:11 +03:00
parent f018970577
commit be27cd1a2e
2 changed files with 145 additions and 107 deletions

View File

@ -33,15 +33,9 @@
/*** file scope macro definitions ****************************************************************/ /*** file scope macro definitions ****************************************************************/
#define shell_escape_toesc(x) \ #define ESCAPE_SHELL_CHARS " !#$%()&~{}[]`?|<>;*\\\""
(((x)==' ')||((x)=='!')||((x)=='#')||((x)=='$')||((x)=='%')|| \ #define ESCAPE_REGEX_CHARS "^!#$%()&~{}[]`?|<>;*.\\"
((x)=='(')||((x)==')')||((x)=='\'')||((x)=='&')||((x)=='~')|| \ #define ESCAPE_GLOB_CHARS "${}*."
((x)=='{')||((x)=='}')||((x)=='[')||((x)==']')||((x)=='`')|| \
((x)=='?')||((x)=='|')||((x)=='<')||((x)=='>')||((x)==';')|| \
((x)=='*')||((x)=='\\')||((x)=='"'))
#define shell_escape_nottoesc(x) \
(((x)!=0) && (!shell_escape_toesc((x))))
/*** file scope type declarations ****************************************************************/ /*** file scope type declarations ****************************************************************/
@ -51,6 +45,111 @@
/*** public functions ****************************************************************************/ /*** public functions ****************************************************************************/
char *
strutils_escape (const char *src, int src_len, const char *escaped_chars,
gboolean escape_non_printable)
{
GString *ret;
gsize loop;
/* do NOT break allocation semantics */
if (src == NULL)
return NULL;
if (*src == '\0')
return strdup ("");
ret = g_string_new ("");
if (src_len == -1)
src_len = strlen (src);
for (loop = 0; loop < src_len; loop++) {
if (escape_non_printable) {
switch (src[loop]) {
case '\n':
g_string_append (ret, "\\n");
continue;
break;
case '\t':
g_string_append (ret, "\\t");
continue;
break;
case '\b':
g_string_append (ret, "\\b");
continue;
break;
case '\0':
g_string_append (ret, "\\0");
continue;
break;
}
}
if (strchr (escaped_chars, (int) src[loop]))
g_string_append_c (ret, '\\');
g_string_append_c (ret, src[loop]);
}
return g_string_free (ret, FALSE);
}
/* --------------------------------------------------------------------------------------------- */
char *
strutils_unescape (const char *src, int src_len, const char *unescaped_chars,
gboolean unescape_non_printable)
{
GString *ret;
gsize loop;
if (src == NULL)
return NULL;
if (*src == '\0')
return strdup ("");
ret = g_string_new ("");
if (src_len == -1)
src_len = strlen (src);
for (loop = 0; loop < src_len-1; loop++) {
if (src[loop] != '\\'){
g_string_append_c (ret, src[loop]);
continue;
}
loop++;
if (unescape_non_printable) {
switch (src[loop]) {
case 'n':
g_string_append_c (ret, '\n');
continue;
break;
case 't':
g_string_append_c (ret, '\t');
continue;
break;
case 'b':
g_string_append_c (ret, '\b');
continue;
break;
case '0':
g_string_append (ret, '\0');
continue;
break;
}
}
if (strchr (unescaped_chars, (int) src[loop]) == NULL)
g_string_append_c (ret, '\\');
g_string_append_c (ret, src[loop]);
}
g_string_append_c (ret, src[loop]);
return g_string_free (ret, FALSE);
}
/* --------------------------------------------------------------------------------------------- */
/** To be compatible with the general posix command lines we have to escape /** To be compatible with the general posix command lines we have to escape
strings for the command line strings for the command line
@ -64,38 +163,23 @@
char * char *
strutils_shell_escape (const char *src) strutils_shell_escape (const char *src)
{ {
GString *str; return strutils_escape (src, -1, ESCAPE_SHELL_CHARS, FALSE);
char *result = NULL; }
/* do NOT break allocation semantics */ /* --------------------------------------------------------------------------------------------- */
if (!src)
return NULL;
if (*src == '\0') char *
return strdup (""); strutils_glob_escape (const char *src)
{
return strutils_escape (src, -1, ESCAPE_GLOB_CHARS, TRUE);
}
str = g_string_new (""); /* --------------------------------------------------------------------------------------------- */
/* look for the first char to escape */ char *
while (1) { strutils_regex_escape (const char *src)
char c; {
/* copy over all chars not to escape */ return strutils_escape (src, -1, ESCAPE_REGEX_CHARS, TRUE);
while ((c = (*src)) && shell_escape_nottoesc (c)) {
g_string_append_c (str, c);
src++;
}
/* at this point we either have an \0 or an char to escape */
if (!c) {
result = str->str;
g_string_free (str, FALSE);
return result;
}
g_string_append_c (str, '\\');
g_string_append_c (str, c);
src++;
}
} }
/* --------------------------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------------------------- */
@ -112,78 +196,22 @@ strutils_shell_escape (const char *src)
char * char *
strutils_shell_unescape (const char *text) strutils_shell_unescape (const char *text)
{ {
GString *str; return strutils_unescape (text, -1, ESCAPE_SHELL_CHARS, TRUE);
char *result = NULL; }
const char *readptr;
char c;
if (!text) /* --------------------------------------------------------------------------------------------- */
return NULL;
char *
strutils_glob_unescape (const char *text)
{
return strutils_unescape (text, -1, ESCAPE_GLOB_CHARS, TRUE);
}
/* look for the first \ - that's quick skipover if there's nothing to escape */ /* --------------------------------------------------------------------------------------------- */
readptr = text; char *
while ((*readptr) && ((*readptr) != '\\')) strutils_regex_unescape (const char *text)
readptr++; {
if (!(*readptr)) { return strutils_unescape (text, -1, ESCAPE_REGEX_CHARS, TRUE);
result = g_strdup (text);
return result;
}
str = g_string_new_len (text, readptr - text);
/* if we're here, we're standing on the first '\' */
while ((c = *readptr)) {
if (c == '\\') {
readptr++;
switch ((c = *readptr)) {
case '\0': /* end of string! malformed escape string */
goto out;
case 'n':
g_string_append_c (str, '\n');
break;
case 'r':
g_string_append_c (str, '\r');
break;
case 't':
g_string_append_c (str, '\t');
break;
case ' ':
case '\\':
case '#':
case '$':
case '%':
case '(':
case ')':
case '[':
case ']':
case '{':
case '}':
case '<':
case '>':
case '!':
case '*':
case '?':
case '~':
case '`':
case '"':
case ';':
default:
g_string_append_c (str, c);
break;
}
} else { /* got a normal character */
g_string_append_c (str, c);
}
readptr++;
}
out:
result = str->str;
g_string_free (str, FALSE);
return result;
} }
/* --------------------------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------------------------- */

View File

@ -15,8 +15,18 @@
/*** declarations of public functions ************************************************************/ /*** declarations of public functions ************************************************************/
gboolean strutils_is_char_escaped (const char *); char *strutils_escape (const char *, int, const char *, gboolean);
char *strutils_unescape (const char *, int, const char *, gboolean);
char *strutils_shell_unescape (const char *); char *strutils_shell_unescape (const char *);
char *strutils_shell_escape (const char *); char *strutils_shell_escape (const char *);
char *strutils_glob_escape (const char *);
char *strutils_glob_escape (const char *);
char *strutils_regex_escape (const char *);
char *strutils_regex_escape (const char *);
gboolean strutils_is_char_escaped (const char *, const char *);
#endif #endif