Proper response escaping

This PRQ adds a proper [escaping algorithm][] to `ResponseSink`, so that argument(s) to a `Respond` command are automatically single-quoted if they cannot be expressed without escaping (they contain whitespace, single quotes, double quotes, or backslashes).

For example, the response
```
OHAI playd
```
will be passed through unchanged:
```
OHAI playd
```
because there are no characters in `playd` that need escaping.  However,
```
FILE C:\Music\Someone\The Chicken Song.mp3
```
contains both backslashes and spaces, and becomes:
```
FILE 'C:\Users\Someone\Music\The Chicken Song.mp3'
```
Any single quotes are replaced with the sequence `'\''`, which is probably the easiest way to escape single quotes.  Anything else can be safely left unescaped in single quotes, so we don't do anything fancier than this.  Example:
```
FILE /home/example/music/Don't You Want Me.mp3
```
to
```
FILE '/home/example/music/Don'\''t You Want Me.mp3'
```

The command word is [not escaped][], as it is assumed to contain no special characters.

Other changes in this pull request:
* A test suite for the above quoting algorithm ([header][], [code][]);
* A new method, [`ResponseSink::RespondArgs`][], for sending zero (as in [`END`][]) or more-than-one arguments (as in [`FEATURES`][]) in a response;
* Several `ResponseSink` methods are [no longer `const`][], to allow implementations, such as the [dummy `ResponseSink`][] used for testing, that mutate their own state when a response is sent;
* `FEATURES` and `END` now use `RespondArgs`, and the features set is now expressed as [a list][];
* Made `FILE` be announced [on loading][], as originally intended.

Things to do:
* [ ] `clang-format`
* [ ] `doxygen` check
* [ ] Some code review

[escaping algorithm]: https://github.com/UniversityRadioYork/ury-playd/blob/a46fd29c501f3c168bfb04eca496292b9b510dd2/src/io/io_response.cpp#L51-L73
[not escaped]: https://github.com/UniversityRadioYork/ury-playd/blob/a46fd29c501f3c168bfb04eca496292b9b510dd2/src/io/io_response.cpp#L38
[header]: https://github.com/UniversityRadioYork/ury-playd/blob/a46fd29c501f3c168bfb04eca496292b9b510dd2/src/tests/io_response.hpp
[code]: https://github.com/UniversityRadioYork/ury-playd/blob/a46fd29c501f3c168bfb04eca496292b9b510dd2/src/tests/io_response.cpp
[`END`]: https://github.com/UniversityRadioYork/ury-playd/blob/a46fd29c501f3c168bfb04eca496292b9b510dd2/src/player/player.cpp#L83-L85
[`FEATURES`]: https://github.com/UniversityRadioYork/ury-playd/blob/a46fd29c501f3c168bfb04eca496292b9b510dd2/src/player/player.cpp#L67
[no longer `const`]: https://github.com/UniversityRadioYork/ury-playd/commit/5c38704a4d661b7af7135b3a195a518230122b77
[dummy `ResponseSink`]: https://github.com/UniversityRadioYork/ury-playd/blob/a46fd29c501f3c168bfb04eca496292b9b510dd2/src/tests/io_response.hpp#L14-L29
[`ResponseSink::RespondArgs`]: https://github.com/UniversityRadioYork/ury-playd/blob/a46fd29c501f3c168bfb04eca496292b9b510dd2/src/io/io_response.cpp#L35-L44
[a list]: https://github.com/UniversityRadioYork/ury-playd/blob/a46fd29c501f3c168bfb04eca496292b9b510dd2/src/player/player.cpp#L27-L33
[on loading]: https://github.com/UniversityRadioYork/ury-playd/blob/a46fd29c501f3c168bfb04eca496292b9b510dd2/src/player/player_file.cpp#L35-L36
Probably not, I think it might be a hold-over from when I was thinking of using find algorithms to see if there was a need to escape.