mirror of https://github.com/FreeRDP/FreeRDP
Added CommandLineParseCommaSeparatedValuesEx single quote support
This commit is contained in:
parent
34c5b65064
commit
6e2c5f2273
|
@ -483,10 +483,23 @@ const COMMAND_LINE_ARGUMENT_A* CommandLineFindNextArgumentA(const COMMAND_LINE_A
|
|||
return nextArgument;
|
||||
}
|
||||
|
||||
static size_t get_element_count(const char* list, BOOL* failed)
|
||||
static int is_quoted(char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
return 1;
|
||||
case '\'':
|
||||
return -1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t get_element_count(const char* list, BOOL* failed, BOOL fullquoted)
|
||||
{
|
||||
size_t count = 0;
|
||||
BOOL quoted = FALSE;
|
||||
int quoted = 0;
|
||||
BOOL finished = FALSE;
|
||||
BOOL first = TRUE;
|
||||
const char* it = list;
|
||||
|
@ -502,7 +515,7 @@ static size_t get_element_count(const char* list, BOOL* failed)
|
|||
switch (*it)
|
||||
{
|
||||
case '\0':
|
||||
if (quoted)
|
||||
if (quoted != 0)
|
||||
{
|
||||
WLog_ERR(TAG, "Invalid argument (missing closing quote) '%s'", list);
|
||||
*failed = TRUE;
|
||||
|
@ -510,14 +523,23 @@ static size_t get_element_count(const char* list, BOOL* failed)
|
|||
}
|
||||
finished = TRUE;
|
||||
break;
|
||||
case '\'':
|
||||
case '"':
|
||||
if (!quoted && !first)
|
||||
if (!fullquoted)
|
||||
{
|
||||
WLog_ERR(TAG, "Invalid argument (misplaced quote) '%s'", list);
|
||||
*failed = TRUE;
|
||||
return 0;
|
||||
int now = is_quoted(*it);
|
||||
if ((quoted == 0) && !first)
|
||||
{
|
||||
WLog_ERR(TAG, "Invalid argument (misplaced quote) '%s'", list);
|
||||
*failed = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (now == quoted)
|
||||
quoted = 0;
|
||||
else if (quoted == 0)
|
||||
quoted = now;
|
||||
}
|
||||
quoted = !quoted;
|
||||
break;
|
||||
case ',':
|
||||
if (first)
|
||||
|
@ -526,7 +548,7 @@ static size_t get_element_count(const char* list, BOOL* failed)
|
|||
*failed = TRUE;
|
||||
return 0;
|
||||
}
|
||||
if (!quoted)
|
||||
if (quoted == 0)
|
||||
{
|
||||
nextFirst = TRUE;
|
||||
count++;
|
||||
|
@ -542,10 +564,10 @@ static size_t get_element_count(const char* list, BOOL* failed)
|
|||
return count + 1;
|
||||
}
|
||||
|
||||
static char* get_next_comma(char* string)
|
||||
static char* get_next_comma(char* string, BOOL fullquoted)
|
||||
{
|
||||
const char* log = string;
|
||||
BOOL quoted = FALSE;
|
||||
int quoted = 0;
|
||||
BOOL first = TRUE;
|
||||
|
||||
WINPR_ASSERT(string);
|
||||
|
@ -555,17 +577,25 @@ static char* get_next_comma(char* string)
|
|||
switch (*string)
|
||||
{
|
||||
case '\0':
|
||||
if (quoted)
|
||||
if (quoted != 0)
|
||||
WLog_ERR(TAG, "Invalid quoted argument '%s'", log);
|
||||
return NULL;
|
||||
|
||||
case '\'':
|
||||
case '"':
|
||||
if (!quoted && !first)
|
||||
if (!fullquoted)
|
||||
{
|
||||
WLog_ERR(TAG, "Invalid quoted argument '%s'", log);
|
||||
return NULL;
|
||||
int now = is_quoted(*string);
|
||||
if ((quoted == 0) && !first)
|
||||
{
|
||||
WLog_ERR(TAG, "Invalid quoted argument '%s'", log);
|
||||
return NULL;
|
||||
}
|
||||
if (now == quoted)
|
||||
quoted = 0;
|
||||
else if (quoted == 0)
|
||||
quoted = now;
|
||||
}
|
||||
quoted = !quoted;
|
||||
break;
|
||||
|
||||
case ',':
|
||||
|
@ -574,7 +604,7 @@ static char* get_next_comma(char* string)
|
|||
WLog_ERR(TAG, "Invalid argument (empty list elements) '%s'", log);
|
||||
return NULL;
|
||||
}
|
||||
if (!quoted)
|
||||
if (quoted == 0)
|
||||
return string;
|
||||
break;
|
||||
|
||||
|
@ -588,6 +618,41 @@ static char* get_next_comma(char* string)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static BOOL is_valid_fullquoted(const char* string)
|
||||
{
|
||||
char cur = '\0';
|
||||
char last = '\0';
|
||||
const char quote = *string++;
|
||||
|
||||
/* We did not start with a quote. */
|
||||
if (is_quoted(quote) == 0)
|
||||
return FALSE;
|
||||
|
||||
while ((cur = *string++) != '\0')
|
||||
{
|
||||
/* A quote is found. */
|
||||
if (cur == quote)
|
||||
{
|
||||
/* If the quote was escaped, it is valid. */
|
||||
if (last != '\\')
|
||||
{
|
||||
/* Only allow unescaped quote as last character in string. */
|
||||
if (*string != '\0')
|
||||
return FALSE;
|
||||
}
|
||||
/* If the last quote in the string is escaped, it is wrong. */
|
||||
else if (*string != '\0')
|
||||
return FALSE;
|
||||
}
|
||||
last = cur;
|
||||
}
|
||||
|
||||
/* The string did not terminate with the same quote as it started. */
|
||||
if (last != quote)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
char** CommandLineParseCommaSeparatedValuesEx(const char* name, const char* list, size_t* count)
|
||||
{
|
||||
char** p = NULL;
|
||||
|
@ -600,6 +665,7 @@ char** CommandLineParseCommaSeparatedValuesEx(const char* name, const char* list
|
|||
BOOL failed = FALSE;
|
||||
char* copy = NULL;
|
||||
char* unquoted = NULL;
|
||||
BOOL fullquoted = FALSE;
|
||||
|
||||
if (count == NULL)
|
||||
goto fail;
|
||||
|
@ -607,20 +673,35 @@ char** CommandLineParseCommaSeparatedValuesEx(const char* name, const char* list
|
|||
*count = 0;
|
||||
if (list)
|
||||
{
|
||||
int start, end;
|
||||
unquoted = copy = _strdup(list);
|
||||
if (!copy)
|
||||
goto fail;
|
||||
|
||||
len = strlen(unquoted);
|
||||
if ((unquoted[0] == '"') && (unquoted[len - 1] == '"'))
|
||||
if (len > 0)
|
||||
{
|
||||
unquoted[len - 1] = '\0';
|
||||
unquoted++;
|
||||
len -= 2;
|
||||
start = is_quoted(unquoted[0]);
|
||||
end = is_quoted(unquoted[len - 1]);
|
||||
|
||||
if ((start != 0) && (end != 0))
|
||||
{
|
||||
if (start != end)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid argument (quote mismatch) '%s'", list);
|
||||
goto fail;
|
||||
}
|
||||
if (!is_valid_fullquoted(unquoted))
|
||||
goto fail;
|
||||
unquoted[len - 1] = '\0';
|
||||
unquoted++;
|
||||
len -= 2;
|
||||
fullquoted = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*count = get_element_count(unquoted, &failed);
|
||||
*count = get_element_count(unquoted, &failed, fullquoted);
|
||||
if (failed)
|
||||
goto fail;
|
||||
|
||||
|
@ -671,9 +752,10 @@ char** CommandLineParseCommaSeparatedValuesEx(const char* name, const char* list
|
|||
for (index = name ? 1 : 0; index < nArgs; index++)
|
||||
{
|
||||
char* ptr = str;
|
||||
char* comma = get_next_comma(str);
|
||||
const int quote = is_quoted(*ptr);
|
||||
char* comma = get_next_comma(str, fullquoted);
|
||||
|
||||
if (*ptr == '"')
|
||||
if ((quote != 0) && !fullquoted)
|
||||
ptr++;
|
||||
|
||||
p[index] = ptr;
|
||||
|
@ -681,8 +763,20 @@ char** CommandLineParseCommaSeparatedValuesEx(const char* name, const char* list
|
|||
if (comma)
|
||||
{
|
||||
char* last = comma - 1;
|
||||
if (*last == '"')
|
||||
*last = '\0';
|
||||
const int lastQuote = is_quoted(*last);
|
||||
|
||||
if (!fullquoted)
|
||||
{
|
||||
if (lastQuote != quote)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid argument (quote mismatch) '%s'", list);
|
||||
free(p);
|
||||
p = NULL;
|
||||
goto fail;
|
||||
}
|
||||
else if (lastQuote != 0)
|
||||
*last = '\0';
|
||||
}
|
||||
*comma = '\0';
|
||||
|
||||
str = comma + 1;
|
||||
|
|
|
@ -20,9 +20,10 @@ static const char* testArgv[] = { "mstsc.exe",
|
|||
0 };
|
||||
|
||||
static const char testListAppName[] = "test app name";
|
||||
static const char* testListArgs[] = { "a,b,c,d", "a:,\"b:xxx, yyy\",c", "a:,,,b",
|
||||
"a:,\",b", "\"a,b,c,d d d,fff\"", "",
|
||||
NULL };
|
||||
static const char* testListArgs[] = {
|
||||
"a,b,c,d", "a:,\"b:xxx, yyy\",c", "a:,,,b", "a:,\",b", "\"a,b,c,d d d,fff\"", "",
|
||||
NULL, "'a,b,\",c'", "\"a,b,',c\"", "', a, ', b,c'", "\"a,b,\",c\""
|
||||
};
|
||||
|
||||
static const char* testListArgs1[] = { testListAppName, "a", "b", "c", "d" };
|
||||
static const char* testListArgs2[] = { testListAppName, "a:", "b:xxx, yyy", "c" };
|
||||
|
@ -31,15 +32,34 @@ static const char* testListArgs2[] = { testListAppName, "a:", "b:xxx, yyy", "c"
|
|||
static const char* testListArgs5[] = { testListAppName, "a", "b", "c", "d d d", "fff" };
|
||||
static const char* testListArgs6[] = { testListAppName };
|
||||
static const char* testListArgs7[] = { testListAppName };
|
||||
static const char* testListArgs8[] = { testListAppName, "a", "b", "\"", "c" };
|
||||
static const char* testListArgs9[] = { testListAppName, "a", "b", "'", "c" };
|
||||
// static const char* testListArgs10[] = {};
|
||||
// static const char* testListArgs11[] = {};
|
||||
|
||||
static const char** testListArgsResult[] = {
|
||||
testListArgs1, testListArgs2, NULL /* testListArgs3 */, NULL /* testListArgs4 */, testListArgs5,
|
||||
testListArgs6, testListArgs7
|
||||
};
|
||||
static const char** testListArgsResult[] = { testListArgs1,
|
||||
testListArgs2,
|
||||
NULL /* testListArgs3 */,
|
||||
NULL /* testListArgs4 */,
|
||||
testListArgs5,
|
||||
testListArgs6,
|
||||
testListArgs7,
|
||||
testListArgs8,
|
||||
testListArgs9,
|
||||
NULL /* testListArgs10 */,
|
||||
NULL /* testListArgs11 */ };
|
||||
static const size_t testListArgsCount[] = {
|
||||
ARRAYSIZE(testListArgs1), ARRAYSIZE(testListArgs2), 0 /* ARRAYSIZE(testListArgs3) */,
|
||||
0 /* ARRAYSIZE(testListArgs4) */, ARRAYSIZE(testListArgs5), ARRAYSIZE(testListArgs6),
|
||||
ARRAYSIZE(testListArgs7)
|
||||
ARRAYSIZE(testListArgs1),
|
||||
ARRAYSIZE(testListArgs2),
|
||||
0 /* ARRAYSIZE(testListArgs3) */,
|
||||
0 /* ARRAYSIZE(testListArgs4) */,
|
||||
ARRAYSIZE(testListArgs5),
|
||||
ARRAYSIZE(testListArgs6),
|
||||
ARRAYSIZE(testListArgs7),
|
||||
ARRAYSIZE(testListArgs8),
|
||||
ARRAYSIZE(testListArgs9),
|
||||
0 /* ARRAYSIZE(testListArgs10) */,
|
||||
0 /* ARRAYSIZE(testListArgs11) */
|
||||
};
|
||||
|
||||
static BOOL checkResult(size_t index, char** actual, size_t actualCount)
|
||||
|
|
Loading…
Reference in New Issue