Files
integration/luprex/ext/slash-parser.cpp

168 lines
4.2 KiB
C++
Raw Normal View History

#pragma once
#ifndef DONT_INCLUDE_SLASH_PARSER_HPP
#include "slash-parser.hpp"
#endif
#include <charconv>
#include <sstream>
void SlashCommandParser::skip_white()
{
while ((cursor_ < linelen_) && (ascii_isspace(line_[cursor_])))
{
cursor_++;
}
}
std::string SlashCommandParser::read_word()
{
int start = cursor_;
while ((cursor_ < linelen_) && (!ascii_isspace(line_[cursor_])))
{
cursor_++;
}
std::string result = line_.substr(start, cursor_ - start);
skip_white();
return result;
}
SlashCommandParser::SlashCommandParser(std::string_view Line)
{
line_ = Line;
linelen_ = int(Line.size());
cursor_ = 0;
command_ = read_word();
if ((command_.size() < 2) || (command_[0] != '/'))
{
error_ = "Not a slash-command";
return;
}
if (!ascii_isalpha(command_[1]))
{
error_ = "Slash command must start with ascii alpha";
return;
}
for (int i = 1; i < int(command_.size()); i++)
{
if (!ascii_isalnum(command_[i]))
{
error_ = "Slash-command must be alphanumeric";
return;
}
}
}
bool SlashCommandParser::Parse(std::string_view Command, std::string_view ArgTypes)
{
if (Command != std::string_view(command_)) return false;
args_.clear();
for (int i = 0; i < int(ArgTypes.size()); i++)
{
if (cursor_ == linelen_)
{
std::ostringstream oss;
oss << "Not enough arguments for " << Command << " (need " << ArgTypes.size() << ")";
error_ = oss.str();
return false;
}
switch(ArgTypes[i])
{
case 's':
{
std::string word = read_word();
args_.emplace_back(word);
break;
}
case 'i':
{
std::string word = read_word();
const char *p = word.c_str();
const char *last = p + word.size();
if ((p < last) && (*p == '+')) p++;
int64_t result;
auto r = std::from_chars(p, last, result, 10);
if ((r.ec != std::errc()) || (r.ptr != last))
{
std::ostringstream oss;
oss << Command << " expects arg " << i << " to be an int, not '" << word << "'";
error_ = oss.str();
return false;
}
args_.emplace_back(result);
break;
}
case 'd':
{
std::string word = read_word();
const char *p = word.c_str();
const char *last = p + word.size();
double result;
auto r = std::from_chars(p, last, result);
if ((r.ec != std::errc()) || (r.ptr != last))
{
std::ostringstream oss;
oss << Command << " expects arg " << i << " to be a double, not '" << word << "'";
error_ = oss.str();
return false;
}
args_.emplace_back(result);
break;
}
default:
{
std::ostringstream oss;
oss << "Invalid ArgTypes parameter (" << ArgTypes << ") to Parse routine for " << Command;
error_ = oss.str();
return false;
}
}
}
if (cursor_ != linelen_)
{
error_ = "Too many arguments for command: ";
error_ += Command;
return false;
}
error_.clear();
return true;
}
std::string SlashCommandParser::Error() const
{
if (!error_.empty())
{
return error_;
}
else
{
return std::string("Unrecognized command: ") + command_;
}
}
std::string SlashCommandParser::StringArg(int n) const
{
if ((n < 0) || (n >= int(args_.size()))) return "";
return args_[n].s_;
}
int64_t SlashCommandParser::IntArg(int n) const
{
if ((n < 0) || (n >= int(args_.size()))) return 0;
return args_[n].i_;
}
double SlashCommandParser::DoubleArg(int n) const
{
if ((n < 0) || (n >= int(args_.size()))) return 0.0;
return args_[n].d_;
}