Support quoting of macro arguments (#222)

Single or double quotes can be used in macro arguments
as expected - they denote the begin and the end of the argument.

Example with 2-nd and 3-rd argument in double quotes:
./rpm --define "%foo() 1:%1 2:%2 3:%3" \
         --eval '%foo Next_argument_will_be_empty "" "Last argument"'
1:Next_argument_will_be_empty 2: 3:Last argument

Example with all arguments in single quotes,
without spaces between arguments:

./rpm --define "%foo() 1:%1 2:%2 3:%3" \
         --eval "%foo 'Next argument will be empty''''Last argument'"
1:Next argument will be empty 2: 3:Last argument
This commit is contained in:
Pavlina Moravcova Varekova 2017-07-10 05:21:40 -04:00 committed by Panu Matilainen
parent 9a9eefc40e
commit 47f0a899ef
2 changed files with 119 additions and 1 deletions

View File

@ -649,6 +649,61 @@ freeArgs(MacroBuf mb, int delete)
mb->level--;
}
/* XXX: belongs to argv.c but figure a sensible API before making public */
static ARGV_t argvSplitShell(const char * str, const char * seps)
{
char *dest = NULL;
ARGV_t argv;
int argc = 1;
const char * s;
char * t;
int c;
int quote;
if (str == NULL || seps == NULL)
return NULL;
dest = xmalloc(strlen(str) + 1);
t = dest;
s = str;
argc = 1;
while ((c = *s)) {
if (strchr(seps, c)) {
s++;
} else {
if (!strchr("\"\'",c)) {
/* read argument not in "" or ''*/
for (; (c = *s); s++, t++) {
if (strchr(seps, c) || strchr("\"\'",c))
break;
*t = c;
}
} else {
/* read argument in "" or '' */
quote = *s;
s++;
for (; (c = *s) && (c != quote); t++,s++)
*t = c;
s++;
}
*t = '\0';
t++;
argc++;
}
}
*t = '\0';
argv = xmalloc((argc + 1) * sizeof(*argv));
for (c = 0, s = dest; s < t; s+= strlen(s) + 1) {
argv[c] = xstrdup(s);
c++;
}
argv[c] = NULL;
free(dest);
return argv;
}
/**
* Parse arguments (to next new line) for parameterized macro.
* @todo Use popt rather than getopt to parse args.
@ -685,7 +740,7 @@ grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se,
expandThis(mb, se, lastc-se, &s);
mb->escape = oescape;
argvSplit(&av, s, " \t");
av = argvSplitShell(s, " \t");
argvAppend(&argv, av);
argvFree(av);
free(s);

View File

@ -267,3 +267,66 @@ runroot rpm \
[error: lua script failed: [[string "<lua>"]]:1: exit not permitted in this context]
)
AT_CLEANUP
AT_SETUP([macro arguments in double quotes])
AT_KEYWORDS([macros arguments])
AT_CHECK([
runroot rpm --define "%foo() 1:%1 2:%2" --eval '%foo "argument 1" argument_2'
runroot rpm --define "%foo() 1:%1 2:%2 3:%3 4:%4 5:%5" \
--eval '%foo "argument 1" argument_2 """"""'
runroot rpm \
--define "%foo() 1:%1 2:%2 3:%3 4:%4 5:%5" \
--eval '%foo "arg. number 1""arg. number 2" "arg number 3" "" normal'
runroot rpm \
--define "%foo() 1:%1 2:%2 3:%3 4:%4 5:%5" \
--eval '%foo "arg. number 1"normal"arg. number 2" '
runroot rpm --define "%foo() 1:%1 2:%2 3:%3 4:%4 5:%5" \
--eval '%foo """jjj"""aa"" '
runroot rpm --define "%foo() 1:%1 2:%2 3:%3 4:%4 5:%5" --eval '%foo xx"yy""zz""""bb" '
],
[0],
[1:argument 1 2:argument_2
1:argument 1 2:argument_2 3: 4: 5:
1:arg. number 1 2:arg. number 2 3:arg number 3 4: 5:normal
1:arg. number 1 2:normal 3:arg. number 2 4:%4 5:%5
1: 2:jjj 3: 4:aa 5:
1:xx 2:yy 3:zz 4: 5:bb
])
AT_CLEANUP
AT_SETUP([macro arguments in single + double quotes])
AT_KEYWORDS([macros arguments])
AT_CHECK([
runroot rpm \
--define "%foo() 1:%1 2:%2 3:%3 4:%4 5:%5" \
--eval "%foo 'arg. number 1''arg. number 2' 'arg number 3' '' normal"
runroot rpm \
--define "%foo() 1:%1 2:%2 3:%3 4:%4 5:%5" \
--eval "%foo 'arg. number 1'normal'arg. number 2'''normal "
runroot rpm --define "%foo() 1:%1 2:%2 3:%3 4:%4 5:%5" \
--eval "%foo '''jjj'''aa'' "
runroot rpm --define "%foo() 1:%1 2:%2 3:%3 4:%4 5:%5" \
--eval "%foo ''\"jjj\"''aa\"\" "
runroot rpm --define "%foo() 1:%1 2:%2 3:%3 4:%4 5:%5" --eval "%foo xx'yy''zz''''bb' "
runroot rpm --define "%foo() 1:%1 2:%2 3:%3 4:%4 5:%5" --eval "%foo xx'yy'\"zz\"\"\"'bb' "
],
[0],
[1:arg. number 1 2:arg. number 2 3:arg number 3 4: 5:normal
1:arg. number 1 2:normal 3:arg. number 2 4: 5:normal
1: 2:jjj 3: 4:aa 5:
1: 2:jjj 3: 4:aa 5:
1:xx 2:yy 3:zz 4: 5:bb
1:xx 2:yy 3:zz 4: 5:bb
])
AT_CLEANUP