Skip to content

Commit

Permalink
main: quote output file name before passing it to system(3) function
Browse files Browse the repository at this point in the history
Following command line doesn't work:

      $ ctags -o 'a b' ...

because a shell lauched from system(3) deals a whitespace between 'a'
and 'b' as a separator. The output file name is passed to system(3)
to run external sort command.

This commit adds code to put double and single quoets around the output
file name before passing it to system(3).

The issue is reported by Lorenz Hipp <[email protected]> in a private mail.

Signed-off-by: Masatake YAMATO <[email protected]>
  • Loading branch information
masatake committed Dec 29, 2016
1 parent 6e839be commit e00c55d
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 18 deletions.
1 change: 1 addition & 0 deletions Tmain/abnormal-output-file-names.d/input.c
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
int x;
39 changes: 39 additions & 0 deletions Tmain/abnormal-output-file-names.d/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright: 2016 Masatake YAMATO
# License: GPL-2

CTAGS=$1

rm -f ./"'"
rm -f ./'"'
rm -f ./'$(ls)'
rm -f ./'a b'

${CTAGS} --quiet --options=NONE -o ./"'" --extra=-pF input.c
${CTAGS} --quiet --options=NONE -o ./'"' --extra=-pF input.c
${CTAGS} --quiet --options=NONE -o ./'$(ls)' --extra=-pF input.c
${CTAGS} --quiet --options=NONE -o ./'a b' --extra=-pF input.c

echo '#' SINGLE QUOTE
if [ -e "'" ]; then
cat "'"
fi

echo '#' DOUBLE QUOTES
if [ -e '"' ]; then
cat '"'
fi

echo '#' PROCESS SUBSTITUTION
if [ -e '$(ls)' ]; then
cat '$(ls)'
fi

echo '#' SPACE
if [ -e 'a b' ]; then
cat 'a b'
fi

rm -f ./"'"
rm -f ./'"'
rm -f ./'$(ls)'
rm -f ./'a b'
Empty file.
8 changes: 8 additions & 0 deletions Tmain/abnormal-output-file-names.d/stdout-expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# SINGLE QUOTE
x input.c /^int x;$/;" v typeref:typename:int
# DOUBLE QUOTES
x input.c /^int x;$/;" v typeref:typename:int
# PROCESS SUBSTITUTION
x input.c /^int x;$/;" v typeref:typename:int
# SPACE
x input.c /^int x;$/;" v typeref:typename:int
72 changes: 54 additions & 18 deletions main/sort.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,44 @@ extern void catFile (MIO *mio)
# define PE_CONST const
#endif

/*
Output file name should not be evaluated in system(3) function.
The name must be used as is. Quotations are required to block the
evaluation.
Normal single-quotes are used to quote a cstring:
a => 'a'
" => '"'
If a single-quote is included in the cstring, use double quotes for quoting it.
' => ''"'"''
*/
static void appendCstringWithQuotes (vString *dest, const char* cstr)
{
const char* o;

vStringPut (dest, '\'');
for (o = cstr; *o; o++)
{
if (*o == '\'')
vStringCatS (dest, "'\"'\"'");
else
vStringPut (dest, *o);
}
vStringPut (dest, '\'');
}

extern void externalSortTags (const bool toStdout, MIO *tagFile)
{
const char *const sortNormalCommand = "sort -u";
const char *const sortFoldedCommand = "sort -u -f";
const char *sortCommand =
Option.sorted == SO_FOLDSORTED ? sortFoldedCommand : sortNormalCommand;
# ifndef HAVE_SETENV
PE_CONST char *const sortOrder1 = "LC_COLLATE=C";
PE_CONST char *const sortOrder2 = "LC_ALL=C";
const size_t length = 4 + strlen (sortOrder1) + strlen (sortOrder2) +
strlen (sortCommand) + (2 * strlen (tagFileName ()));
char *const cmd = (char *) malloc (length + 1);
# endif
vString *cmd = vStringNew ();
int ret = -1;

if (cmd != NULL)
Expand All @@ -80,19 +107,29 @@ extern void externalSortTags (const bool toStdout, MIO *tagFile)
putenv (sortOrder1);
putenv (sortOrder2);
# endif
if (toStdout)
sprintf (cmd, "%s", sortCommand);
else
sprintf (cmd, "%s -o %s %s", sortCommand,
tagFileName (), tagFileName ());
vStringCatS (cmd, sortCommand);
if (! toStdout)
{
vStringCatS (cmd, " -o ");
appendCstringWithQuotes (cmd, tagFileName ());
vStringPut (cmd, ' ');
appendCstringWithQuotes (cmd, tagFileName ());
}
#else
if (toStdout)
sprintf (cmd, "%s %s %s", sortOrder1, sortOrder2, sortCommand);
else
sprintf (cmd, "%s %s %s -o %s %s", sortOrder1, sortOrder2,
sortCommand, tagFileName (), tagFileName ());
vStringCatS (cmd, sortOrder1);
vStringPut (cmd, ' ');
vStringCatS (cmd, sortOrder2);
vStringPut (cmd, ' ');
vStringCatS (cmd, sortCommand);
if (! toStdout)
{
vStringCats (cmd, " -o ");
appendCstringWithQuotes (cmd, tagFileName ());
vStringPut (cmd, ' ');
appendCstringWithQuotes (cmd, tagFileName ());
}
#endif
verbose ("system (\"%s\")\n", cmd);
verbose ("system (\"%s\")\n", vStringValue (cmd));
if (toStdout)
{
const int fdstdin = 0;
Expand All @@ -105,15 +142,14 @@ extern void externalSortTags (const bool toStdout, MIO *tagFile)
error (FATAL | PERROR, "cannot redirect stdin");
if (lseek (fdstdin, 0, SEEK_SET) != 0)
error (FATAL | PERROR, "cannot rewind tag file");
ret = system (cmd);
ret = system (vStringValue (cmd));
if (dup2 (fdsave, fdstdin) < 0)
error (FATAL | PERROR, "cannot restore stdin fd");
close (fdsave);
}
else
ret = system (cmd);
free (cmd);

ret = system (vStringValue (cmd));
vStringDelete (cmd);
}
if (ret != 0)
error (FATAL | PERROR, "cannot sort tag file");
Expand Down

0 comments on commit e00c55d

Please sign in to comment.