[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
new module 'system-quote'
From: |
Bruno Haible |
Subject: |
new module 'system-quote' |
Date: |
Wed, 09 May 2012 03:37:27 +0200 |
User-agent: |
KMail/4.7.4 (Linux/3.1.10-1.9-desktop; KDE/4.7.4; x86_64; ; ) |
This is the module 'system-quote'.
It turns out that on native Windows, when going through cmd.exe, it is
not possible to pass arguments that contains a newline ('\n') or a CR ('\r')
character: the command gets truncated at such a character. Compared to
this problem, the handling of the '%' character is easy.
2012-05-08 Bruno Haible <address@hidden>
New module 'system-quote'.
* lib/system-quote.h: New file.
* lib/system-quote.c: New file.
* modules/system-quote: New file.
============================= lib/system-quote.h =============================
/* Quoting for a system command.
Copyright (C) 2001-2012 Free Software Foundation, Inc.
Written by Bruno Haible <address@hidden>, 2012.
This program 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.
This program 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/>. */
#ifndef _SYSTEM_QUOTE_H
#define _SYSTEM_QUOTE_H
/* When passing a command the system's command interpreter, we must quote the
program name and arguments, since
- Unix shells interpret characters like " ", "'", "<", ">", "$" etc. in a
special way,
- Windows CreateProcess() interprets characters like ' ', '\t', '\\', '"'
etc. (but not '<' and '>') in a special way,
- Windows cmd.exe also interprets characters like '<', '>', '&', '%', etc.
in a special way. Note that it is impossible to pass arguments that
contain newlines or carriage return characters to programs through
cmd.exe. */
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Identifier for the kind of interpreter of the command. */
enum system_command_interpreter
{
/* The interpreter used by the system() and popen() functions.
This is equivalent to SCI_POSIX_SH on Unix platforms and
SCI_WINDOWS_CMD on native Windows platforms. */
SCI_SYSTEM = 0
/* The POSIX /bin/sh. */
, SCI_POSIX_SH = 1
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
/* The native Windows CreateProcess() function. */
, SCI_WINDOWS_CREATEPROCESS = 2
/* The native Windows cmd.exe interpreter. */
, SCI_WINDOWS_CMD = 3
#endif
};
/* Returns the number of bytes needed for the quoted string. */
extern size_t
system_quote_length (enum system_command_interpreter interpreter,
const char *string);
/* Copies the quoted string to p and returns the incremented p.
There must be room for shell_quote_length (string) + 1 bytes at p. */
extern char *
system_quote_copy (char *p,
enum system_command_interpreter interpreter,
const char *string);
/* Returns the freshly allocated quoted string. */
extern char *
system_quote (enum system_command_interpreter interpreter,
const char *string);
/* Returns a freshly allocated string containing all argument strings, quoted,
separated through spaces. */
extern char *
system_quote_argv (enum system_command_interpreter interpreter,
char * const *argv);
#ifdef __cplusplus
}
#endif
#endif /* _SYSTEM_QUOTE_H */
============================= lib/system-quote.c =============================
/* Quoting for a system command.
Copyright (C) 2012 Free Software Foundation, Inc.
Written by Bruno Haible <address@hidden>, 2012.
This program 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.
This program 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>
/* Specification. */
#include "system-quote.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "sh-quote.h"
#include "xalloc.h"
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
/* The native Windows CreateProcess() function interprets characters like
' ', '\t', '\\', '"' (but not '<' and '>') in a special way:
- Space and tab are interpreted as delimiters. They are not treated as
delimiters if they are surrounded by double quotes: "...".
- Unescaped double quotes are removed from the input. Their only effect is
that within double quotes, space and tab are treated like normal
characters.
- Backslashes not followed by double quotes are not special.
- But 2*n+1 backslashes followed by a double quote become
n backslashes followed by a double quote (n >= 0):
\" -> "
\\\" -> \"
\\\\\" -> \\"
- '*' characters may get expanded or lead to a failure with error code
ERROR_PATH_NOT_FOUND.
*/
# define SHELL_SPECIAL_CHARS "\"\\
\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037*"
# define SHELL_SPACE_CHARS "
\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
/* The native Windows cmd.exe command interpreter also interprets:
- '\n', '\r' as a command terminator - no way to escape it,
- '<', '>' as redirections,
- '|' as pipe operator,
- '%var%' as a reference to the environment variable VAR (uppercase),
even inside quoted strings,
- '&' '[' ']' '{' '}' '^' '=' ';' '!' '\'' '+' ',' '`' '~' for other
purposes, according to
<http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/cmd.mspx?mfr=true>
We quote a string like '%var%' by putting the '%' characters outside of
double-quotes and the rest of the string inside double-quotes: %"var"%.
This is guaranteed to not be a reference to an environment variable.
*/
# define CMD_SPECIAL_CHARS "\"\\
\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037!%&'*+,;<=>[]^`{|}~"
# define CMD_FORBIDDEN_CHARS "\n\r"
#endif
size_t
system_quote_length (enum system_command_interpreter interpreter,
const char *string)
{
switch (interpreter)
{
#if !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
case SCI_SYSTEM:
#endif
case SCI_POSIX_SH:
return shell_quote_length (string);
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
case SCI_WINDOWS_CREATEPROCESS:
{
size_t len = strlen (string);
bool quote_around =
(len == 0 || strpbrk (string, SHELL_SPECIAL_CHARS) != NULL);
size_t backslashes = 0;
size_t length = len;
if (quote_around)
length++;
for (; len > 0; string++, len--)
{
char c = *string;
if (c == '"')
length += backslashes + 1;
if (c == '\\')
backslashes++;
else
backslashes = 0;
}
if (quote_around)
length += backslashes + 1;
return length;
}
case SCI_SYSTEM:
case SCI_WINDOWS_CMD:
{
size_t len = strlen (string);
bool quote_around =
(len == 0 || strpbrk (string, CMD_SPECIAL_CHARS) != NULL);
size_t backslashes = 0;
size_t length = len;
if (quote_around)
length++;
for (; len > 0; string++, len--)
{
char c = *string;
if (c == '"')
length += backslashes + 1;
if (c == '%')
length += backslashes + 2;
if (c == '\\')
backslashes++;
else
backslashes = 0;
}
if (quote_around)
length += backslashes + 1;
return length;
}
#endif
default:
/* Invalid interpreter. */
abort ();
}
}
char *
system_quote_copy (char *p,
enum system_command_interpreter interpreter,
const char *string)
{
switch (interpreter)
{
#if !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
case SCI_SYSTEM:
#endif
case SCI_POSIX_SH:
return shell_quote_copy (p, string);
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
case SCI_WINDOWS_CREATEPROCESS:
{
size_t len = strlen (string);
bool quote_around =
(len == 0 || strpbrk (string, SHELL_SPECIAL_CHARS) != NULL);
size_t backslashes = 0;
if (quote_around)
*p++ = '"';
for (; len > 0; string++, len--)
{
char c = *string;
if (c == '"')
{
size_t j;
for (j = backslashes + 1; j > 0; j--)
*p++ = '\\';
}
*p++ = c;
if (c == '\\')
backslashes++;
else
backslashes = 0;
}
if (quote_around)
{
size_t j;
for (j = backslashes; j > 0; j--)
*p++ = '\\';
*p++ = '"';
}
*p = '\0';
return p;
}
case SCI_SYSTEM:
case SCI_WINDOWS_CMD:
{
size_t len = strlen (string);
bool quote_around =
(len == 0 || strpbrk (string, CMD_SPECIAL_CHARS) != NULL);
size_t backslashes = 0;
if (quote_around)
*p++ = '"';
for (; len > 0; string++, len--)
{
char c = *string;
if (c == '"')
{
size_t j;
for (j = backslashes + 1; j > 0; j--)
*p++ = '\\';
}
if (c == '%')
{
size_t j;
for (j = backslashes; j > 0; j--)
*p++ = '\\';
*p++ = '"';
}
*p++ = c;
if (c == '%')
*p++ = '"';
if (c == '\\')
backslashes++;
else
backslashes = 0;
}
if (quote_around)
{
size_t j;
for (j = backslashes; j > 0; j--)
*p++ = '\\';
*p++ = '"';
}
*p = '\0';
return p;
}
#endif
default:
/* Invalid interpreter. */
abort ();
}
}
char *
system_quote (enum system_command_interpreter interpreter,
const char *string)
{
switch (interpreter)
{
#if !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
case SCI_SYSTEM:
#endif
case SCI_POSIX_SH:
return shell_quote (string);
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
case SCI_WINDOWS_CREATEPROCESS:
case SCI_SYSTEM:
case SCI_WINDOWS_CMD:
{
size_t length = system_quote_length (interpreter, string);
char *quoted = XNMALLOC (length, char);
system_quote_copy (quoted, interpreter, string);
return quoted;
}
#endif
default:
/* Invalid interpreter. */
abort ();
}
}
char *
system_quote_argv (enum system_command_interpreter interpreter,
char * const *argv)
{
if (*argv != NULL)
{
char * const *argp;
size_t length;
char *command;
char *p;
length = 0;
for (argp = argv; ; )
{
length += system_quote_length (interpreter, *argp) + 1;
argp++;
if (*argp == NULL)
break;
}
command = XNMALLOC (length, char);
p = command;
for (argp = argv; ; )
{
p = system_quote_copy (p, interpreter, *argp);
argp++;
if (*argp == NULL)
break;
*p++ = ' ';
}
*p = '\0';
return command;
}
else
return xstrdup ("");
}
============================ modules/system-quote ============================
Description:
Quoting for a system command.
Files:
lib/system-quote.h
lib/system-quote.c
Depends-on:
sh-quote
xalloc
configure.ac:
Makefile.am:
lib_SOURCES += system-quote.h system-quote.c
Include:
"system-quote.h"
License:
GPL
Maintainer:
Bruno Haible
==============================================================================
- Re: quotearg.c's shell_quoting_style and MinGW, (continued)
- Re: quotearg.c's shell_quoting_style and MinGW, Bruno Haible, 2012/05/06
- Re: quotearg.c's shell_quoting_style and MinGW, Bruno Haible, 2012/05/06
- Re: quotearg.c's shell_quoting_style and MinGW, Paul Eggert, 2012/05/06
- Re: quotearg.c's shell_quoting_style and MinGW, Bruno Haible, 2012/05/06
- Re: quotearg.c's shell_quoting_style and MinGW, Eli Zaretskii, 2012/05/06
- Re: quotearg.c's shell_quoting_style and MinGW, Bruno Haible, 2012/05/06
- Re: quotearg.c's shell_quoting_style and MinGW, Eli Zaretskii, 2012/05/06
- Re: quotearg.c's shell_quoting_style and MinGW, Bruno Haible, 2012/05/06
- new module 'system-quote',
Bruno Haible <=
- Re: new module 'system-quote', Bruno Haible, 2012/05/08
- Re: new module 'system-quote', Eli Zaretskii, 2012/05/09
- Re: new module 'system-quote', Bruno Haible, 2012/05/09
- Re: new module 'system-quote', Eli Zaretskii, 2012/05/09
- Re: new module 'system-quote', Bruno Haible, 2012/05/09
- Re: new module 'system-quote', Eli Zaretskii, 2012/05/10
- Re: new module 'system-quote', Bruno Haible, 2012/05/10
- Re: new module 'system-quote', Eli Zaretskii, 2012/05/10
- Re: new module 'system-quote', Paul Eggert, 2012/05/10
- Re: new module 'system-quote', Eli Zaretskii, 2012/05/10