NAME
shquote,
shquotev —
quote argument strings for use with the shell
LIBRARY
Standard C Library (libc, -lc)
SYNOPSIS
#include <stdlib.h>
size_t
shquote(
const
char *arg,
char *buf,
size_t bufsize);
size_t
shquotev(
int
argc,
char * const
*argv,
char *buf,
size_t bufsize);
DESCRIPTION
The
shquote() and
shquotev() functions copy
strings and transform the copies by adding shell escape and quoting
characters. They are used to encapsulate arguments to be included in command
strings passed to the
system() and
popen()
functions, so that the arguments will have the correct values after being
evaluated by the shell.
The exact method of quoting and escaping may vary, and is intended to match the
conventions of the shell used by
system() and
popen(). It may not match the conventions used by other
shells. In this implementation, the following transformation is applied to
each input string:
- it is surrounded by single quotes ('),
- any single quotes in the input are escaped by replacing
them with the four-character sequence:
'\''
,
and
- extraneous pairs of single quotes (caused by multiple
adjacent single quotes in the input string, or by single quotes at the
beginning or end of the input string) are elided.
The
shquote() function transforms the string specified by its
arg argument, and places the result into the memory
pointed to by
buf.
The
shquotev() function transforms each of the
argc strings specified by the array
argv independently. The transformed strings are placed
in the memory pointed to by
buf, separated by spaces. It
does not modify the pointer array specified by
argv or
the strings pointed to by the pointers in the array.
Both functions write up to
bufsize - 1 characters of
output into the buffer pointed to by
buf, then add a
NUL
character to terminate the output string. If
bufsize is given as zero, the
buf
parameter is ignored and no output is written.
RETURN VALUES
The
shquote() and
shquotev() functions
return the number of characters necessary to hold the result from operating on
their input strings, not including the terminating
NUL
. That is, they return the length of the string
that would have been written to the output buffer, if it were large enough. If
an error occurs during processing, the value ((size_t)-1) is returned and
errno is set appropriately.
EXAMPLES
The following code fragment demonstrates how you might use
shquotev() to construct a command string to be used with
system(). The command uses an environment variable (which
will be expanded by the shell) to determine the actual program to run. Note
that the environment variable may be expanded by the shell into multiple
words. The first word of the expansion will be used by the shell as the name
of the program to run, and the rest will be passed as arguments to the
program.
char **argv, c, *cmd;
size_t cmdlen, len, qlen;
int argc;
...
/*
* Size buffer to hold the command string, and allocate it.
* Buffer of length one given to snprintf() for portability.
*/
cmdlen = snprintf(&c, 1, "${PROG-%s} ", PROG_DEFAULT);
qlen = shquotev(argc, argv, NULL, 0);
if (qlen == (size_t)-1) {
...
}
cmdlen += qlen + 1;
cmd = malloc(cmdlen);
if (cmd == NULL) {
...
}
/* Create the command string. */
len = snprintf(cmd, cmdlen, "${PROG-%s} ", PROG_DEFAULT);
qlen = shquotev(argc, argv, cmd + len, cmdlen - len);
if (qlen == (size_t)-1) {
/* Should not ever happen. */
...
}
len += qlen;
/* "cmd" can now be passed to system(). */
The following example shows how you would implement the same functionality using
the
shquote() function directly.
char **argv, c, *cmd;
size_t cmdlen, len, qlen;
int argc, i;
...
/*
* Size buffer to hold the command string, and allocate it.
* Buffer of length one given to snprintf() for portability.
*/
cmdlen = snprintf(&c, 1, "${PROG-%s} ", PROG_DEFAULT);
for (i = 0; i < argc; i++) {
qlen = shquote(argv[i], NULL, 0);
if (qlen == (size_t)-1) {
...
}
cmdlen += qlen + 1;
}
cmd = malloc(cmdlen);
if (cmd == NULL) {
...
}
/* Start the command string with the env var reference. */
len = snprintf(cmd, cmdlen, "${PROG-%s} ", PROG_DEFAULT);
/* Quote all of the arguments when copying them. */
for (i = 0; i < argc; i++) {
qlen = shquote(argv[i], cmd + len, cmdlen - len);
if (qlen == (size_t)-1) {
/* Should not ever happen. */
...
}
len += qlen;
cmd[len++] = ' ';
}
cmd[--len] = '\0';
/* "cmd" can now be passed to system(). */
SEE ALSO
sh(1),
popen(3),
system(3)
BUGS
This implementation does not currently handle strings containing multibyte
characters properly. To address this issue,
/bin/sh (the
shell used by
system() and
popen()) must
first be fixed to handle multibyte characters. When that has been done, these
functions can have multibyte character support enabled.