input: arguments quoting: support single-quotes

Users expect single quotes to work when the value includes literal
backslashes or double-quotes (or as general quoting like in shell).

The updated docs also include some previously-missing notes:
- newline is only supported in double quotes.
- adjacent (quoted) arguments don't join into one.

Supporting mixed quoting (adjacent quoted strings) would make
mpv's parsing more complete, but would require delicate effort of
larger scope, for two reasons:
- We'd need to also support escaping outside of quotes and do our
  best about backward compatibility.
- The parsed value can either be a substring of the input or
  a newly-allocated string, which would be delicate when joining.

Not critical to add right now.
This commit is contained in:
Avi Halachmi (:avih) 2021-07-28 12:29:08 +03:00 committed by avih
parent 73c9509720
commit 9f6cbf3a4d
2 changed files with 26 additions and 9 deletions

View File

@ -162,7 +162,7 @@ a number of other places.
|
| ``<command> ::= [<prefixes>] <command_name> (<argument>)*``
| ``<argument> ::= (<unquoted> | " <double_quoted> " | `X <custom_quoted> X`)``
| ``<argument> ::= (<unquoted> | " <double_quoted> " | ' <single_quoted> ' | `X <custom_quoted> X`)``
``command_name`` is an unquoted string with the command name itself. See
`List of Input Commands`_ for a list.
@ -171,14 +171,21 @@ Arguments are separated by whitespaces even if the command expects only one
argument. Arguments with whitespaces or other special characters must be quoted,
or the command cannot be parsed correctly.
Double quoted arguments start and end with ``"``. Custom quotes start with `````
(back-quote) followed by any ASCII character, and end in the same pair in
reverse order, e.g. ```-foo-``` or ````bar````. The final pair sequence is not
allowed inside the string - in these examples ``-``` and `````` respectively.
Double quotes interpret JSON/C-style escaping, like ``\t`` or ``\"`` or ``\\``.
JSON escapes according to RFC 8259, minus surrogate pair escapes. This is the
only form which allows newlines at the value - as ``\n``.
Custom quotes take their content literally, while inside double quotes
JSON/C-style escaping can be used. JSON escapes according to RFC 8259, minus
surrogate pair escapes, should be a safe subset that can be used.
Single quotes take the content literally, and cannot include the single-quote
character at the value.
Custom quotes also take the content literally, but are more flexible than single
quotes. They start with ````` (back-quote) followed by any ASCII character,
and end at the first occurance of the same pair in reverse order, e.g.
```-foo-``` or ````bar````. The final pair sequence is not allowed at the
value - in these examples ``-``` and `````` respectively. In the second
example the last character of the value also can't be a back-quote.
Mixed quoting at the same argument, like ``'foo'"bar"``, is not supported.
Note that argument parsing and property expansion happen at different stages.
First, arguments are determined as described above, and then, where applicable,

View File

@ -336,11 +336,21 @@ static int pctx_read_token(struct parse_ctx *ctx, bstr *out)
return -1;
}
if (!bstr_eatstart0(&ctx->str, "\"")) {
MP_ERR(ctx, "Unterminated quotes: ...>%.*s<.\n", BSTR_P(start));
MP_ERR(ctx, "Unterminated double quote: ...>%.*s<.\n", BSTR_P(start));
return -1;
}
return 1;
}
if (bstr_eatstart0(&ctx->str, "'")) {
int next = bstrchr(ctx->str, '\'');
if (next < 0) {
MP_ERR(ctx, "Unterminated single quote: ...>%.*s<.\n", BSTR_P(start));
return -1;
}
*out = bstr_splice(ctx->str, 0, next);
ctx->str = bstr_cut(ctx->str, next+1);
return 1;
}
if (ctx->start.len > 1 && bstr_eatstart0(&ctx->str, "`")) {
char endquote[2] = {ctx->str.start[0], '`'};
ctx->str = bstr_cut(ctx->str, 1);