Re: re-quoting (aka reconstituting a command line)
- From: Adam Kellas <adam.kellas@xxxxxxxxx>
- Date: Mon, 21 Sep 2009 18:22:31 -0700 (PDT)
On Sep 21, 1:37 pm, Marcel Bruinsma <m...@xxxxxxxxxxxxxxxxx> wrote:
Alternative (alnums are probably more frequent),
for (quote = '\0', c = word; *c; c++) {
if (!isalnum((int)*c)) {
if (strchr("\"\\$`", (int)*c)) {
Nice idea, applied.
The memory allocated by malloc(3) is not cleared,
*ptr++ = argv[1] ? ' ' : '\0';
or
*ptr++ = ' '; // Add space unconditionally
}
*--ptr = '\0'; // Extra space => end of string
return cmdline;
Thanks. Turns out I had this one right in my "real" code but had lost
it in the sample program.
The following is my - well, I hesitate to say "final" version but I
think it's closing in on being correct:
// gcc -o requote -W -Wall -g requote.c
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
static char *
requote(char **argv)
{
char *word, *cmdline, *ptr, *c;
int extra_s, extra_d, quote, i;
size_t cmdlen;
// Figure out the worst-case scenario for how much space the
cmdline
// will need and allocate that much.
for (cmdlen = 0, i = 0; argv[i]; i++) {
// If every character is a single-quote and we use single quotes;
// this is a very pessimistic strategy.
cmdlen += (strlen(argv[i]) * 4) + 4;
}
cmdline = malloc(cmdlen);
// There are 4 viable POSIX quoting strategies: (1) use only
// backslashes (no quotes), (2) use double quotes and escape
// as required, (3) use single quotes and special-case
// embedded single quotes, (4) use a hybrid strategy of examining
// the word and choosing the simplest of single, double, or none.
// The following represents the hybrid approach.
for (ptr = cmdline; (word = *argv); argv++) {
// First, figure out what kind of quotes we want if any.
// We need _some_ metric by which to choose quoting style;
// the current one is to assume that the most elegant
// quoting is that which requires the fewest characters.
// Therefore we count the number of extra chars required
// for a single- or double-quoting decision, and choose the
// one which requires the fewest (or no quotes at all if
// they're both zero).
// There are a very few characters which make single-quoting
// preferable; otherwise, if any character is not on the
// list of known inert chars, we play it safe and issue a
// vote for double-quoting. Double-quoting will generally
// win unless there's a preponderance of that smaller set.
for (extra_s = extra_d = 0, c = word; *c; c++) {
if (strchr("$\"\\`", *c)) {
extra_s += 4;
extra_d += 1;
} else if (!isalnum((int)*c)) {
if (!strchr("!%+,-./=:@_", *c)) {
extra_d += 1;
extra_s += 1;
}
}
}
if (extra_s || extra_d) {
quote = (extra_d > extra_s) ? '\'' : '"';
} else {
quote = 0;
}
// Add opening quote if required.
if (quote) {
*ptr++ = quote;
}
// Copy the current word into the output buffer with adjustments.
for (; *word; word++) {
int chr;
switch((chr = *word)) {
case '\b': *ptr++ = '\\'; chr = 'b'; break;
case '\f': *ptr++ = '\\'; chr = 'f'; break;
case '\r': *ptr++ = '\\'; chr = 'r'; break;
case '$':
case '`':
case '"':
if (quote == '"') {
*ptr++ = '\\';
}
break;
case '\'':
if (quote == '\'') {
*ptr++ = '\'';
*ptr++ = '\\';
*ptr++ = '\'';
}
break;
default:
break;
}
*ptr++ = chr;
}
// Add closing quote if required.
if (quote) {
*ptr++ = quote;
}
// Add space if required.
if (argv[1]) {
*ptr++ = ' ';
} else {
*ptr = '\0';
}
}
// Trim to fit
cmdline = realloc(cmdline, strlen(cmdline) + 1);
return cmdline;
}
int
main(int argc, char **argv)
{
char *cmd;
int rc = 0;
argv[0] = "echo";
cmd = requote(argv);
fprintf(stderr, "==[%d]%s==\n", argc, cmd);
rc = system(cmd);
free(cmd);
return rc;
}
.
- Follow-Ups:
- Re: re-quoting (aka reconstituting a command line)
- From: Marcel Bruinsma
- Re: re-quoting (aka reconstituting a command line)
- References:
- Re: re-quoting (aka reconstituting a command line)
- From: Adam Kellas
- Re: re-quoting (aka reconstituting a command line)
- From: Marcel Bruinsma
- Re: re-quoting (aka reconstituting a command line)
- From: Adam Kellas
- Re: re-quoting (aka reconstituting a command line)
- From: Marcel Bruinsma
- Re: re-quoting (aka reconstituting a command line)
- Prev by Date: transferring files to /etc and /usr/local/bin via bash script on OSX 10.5
- Next by Date: Re: transferring files to /etc and /usr/local/bin via bash script on OSX 10.5
- Previous by thread: Re: re-quoting (aka reconstituting a command line)
- Next by thread: Re: re-quoting (aka reconstituting a command line)
- Index(es):
Relevant Pages
|