* Execute a given command passed to us. First chop it up into * individual tokens (separated by spaces), then execute it if possible * @param command_string string to be parsed and executed */
| 267 | * @param command_string string to be parsed and executed |
| 268 | */ |
| 269 | void IConsoleCmdExec(std::string_view command_string, const uint recurse_count) |
| 270 | { |
| 271 | if (command_string[0] == '#') return; // comments |
| 272 | |
| 273 | Debug(console, 4, "Executing cmdline: '{}'", command_string); |
| 274 | |
| 275 | std::string buffer; |
| 276 | StringBuilder builder{buffer}; |
| 277 | StringConsumer consumer{command_string}; |
| 278 | |
| 279 | std::vector<std::string> tokens; |
| 280 | bool found_token = false; |
| 281 | bool in_quotes = false; |
| 282 | |
| 283 | /* 1. Split up commandline into tokens, separated by spaces, commands |
| 284 | * enclosed in "" are taken as one token. We can only go as far as the amount |
| 285 | * of characters in our stream or the max amount of tokens we can handle */ |
| 286 | while (consumer.AnyBytesLeft()) { |
| 287 | auto c = consumer.TryReadUtf8(); |
| 288 | if (!c.has_value()) { |
| 289 | IConsolePrint(CC_ERROR, "Command '{}' contains malformed characters.", command_string); |
| 290 | return; |
| 291 | } |
| 292 | |
| 293 | switch (*c) { |
| 294 | case ' ': // Token separator |
| 295 | if (!found_token) break; |
| 296 | |
| 297 | if (in_quotes) { |
| 298 | builder.PutUtf8(*c); |
| 299 | break; |
| 300 | } |
| 301 | |
| 302 | tokens.emplace_back(std::move(buffer)); |
| 303 | buffer.clear(); |
| 304 | found_token = false; |
| 305 | break; |
| 306 | |
| 307 | case '"': // Tokens enclosed in "" are one token |
| 308 | in_quotes = !in_quotes; |
| 309 | found_token = true; |
| 310 | break; |
| 311 | |
| 312 | case '\\': // Escape character for "" |
| 313 | if (consumer.ReadUtf8If('"')) { |
| 314 | builder.PutUtf8('"'); |
| 315 | break; |
| 316 | } |
| 317 | [[fallthrough]]; |
| 318 | |
| 319 | default: // Normal character |
| 320 | builder.PutUtf8(*c); |
| 321 | found_token = true; |
| 322 | break; |
| 323 | } |
| 324 | } |
| 325 | |
| 326 | if (found_token) { |
no test coverage detected