24 #ifndef SCID_PGNPARSE_H    25 #define SCID_PGNPARSE_H    41     std::vector<std::pair<size_t, std::string>> errors_;
    43     int nErrorsAllowed_ = 2;
    45     using TView = std::pair<const char*, const char*>;
    52         if (nErrorsAllowed_ < 0) 
    55         return logErr(
"Unexpected end of input (result missing ?).");
    59         if (nErrorsAllowed_ < 0) 
    62         return logErr(
"Unexpected end of game: PGN header '[' seen "    63                       "inside game (result missing ?).");
    67         if (nErrorsAllowed_ < 0) { 
    68             linenum_ += std::count(comment.first, comment.second, 
'\n');
    74         auto prevSz = str.size();
    75         str.append(comment.first, comment.second);
    86         ASSERT(nErrorsAllowed_ >= 0);
    87         std::string tmp(line.first, line.second);
    89             return logErr(
"Failed to parse EPD record: ", line);
    92         auto opcode = std::find_if(line.first, line.second, [&](
char ch) {
    93             return (ch == 
' ') ? spaces++ == 4 : spaces == 4;
   103         if (nErrorsAllowed_ < 0) 
   107         if (nag_code == 0 || game.
AddNag(nag_code) != 
OK)
   108             return logErr(
"Invalid annotation symbol: ", token);
   130         if (result != prev_result) {
   133             if (prev_result != 
RESULT_None && nErrorsAllowed_ >= 0)
   134                 logErr(
"Final result did not match the header tag.");
   140         if (nErrorsAllowed_ < 0) 
   147                 logWarning(
"Warning: illegal castling ", tok);
   152                 return logFatalErr(
"Failed to parse the move: ", tok);
   157                    : logFatalErr(
"Failed to add the move: ", tok);
   163         linenum_ += std::count(value.first, value.second, 
'\n');
   164         if (nErrorsAllowed_ < 0) 
   167         auto tagLen = std::distance(tag.first, tag.second);
   168         auto valueLen = std::distance(value.first, value.second);
   169         if (tagLen == 0 || tagLen + valueLen > 240 ||
   170             !parseTagPair(tag.first, tagLen, value)) 
   172             std::string err(tag.first, tag.second);
   174             err.append(value.first, value.second);
   176             logErr(
"Error parsing the tag pair: ",
   177                    {err.c_str(), err.c_str() + err.size()});
   183         if (nErrorsAllowed_ < 0) 
   187         std::string tmp(token.first, token.second);
   188         if (tmp == 
"0-0" || tmp == 
"00") {
   192         if (tmp == 
"0-0-0" || tmp == 
"000") {
   197         return logErr(
"Unknown token: ", token);
   201         if (nErrorsAllowed_ < 0) 
   205             return logFatalErr(
"Failed to add a new variation.");
   211         if (nErrorsAllowed_ < 0) 
   215             return logFatalErr(
"Failed to exit from variation.");
   221     bool logWarning(
const char* str1, TView str2 = {
nullptr, 
nullptr}) {
   222         errors_.emplace_back(linenum_, str1);
   223         if (std::distance(str2.first, str2.second) > 200) {
   224             errors_.back().second.append(str2.first, 200);
   225             errors_.back().second.append(
"...");
   227             errors_.back().second.append(str2.first, str2.second);
   232     bool logErr(
const char* str1, TView str2 = {
nullptr, 
nullptr}) {
   234         return logWarning(str1, str2);
   237     bool logFatalErr(
const char* str1, TView str2 = {
nullptr, 
nullptr}) {
   239         return logErr(str1, str2);
   242     bool parseTagResult(TView str) {
   243         auto len = std::distance(str.first, str.second);
   244         if (len > 0 && *str.first == 
'*') {
   249             if (std::equal(str.first, str.first + 3, 
"1-0")) {
   253             if (std::equal(str.first, str.first + 3, 
"0-1")) {
   257             if (std::equal(str.first, str.first + 3, 
"1/2")) {
   262         return logErr(
"Invalid Result tag: ", str);
   265     bool parseTagPair(
const char* tag, 
size_t tagLen, TView value) {
   268             if (std::equal(tag, tag + 3, 
"ECO")) {
   269                 std::string tmp{value.first, value.second};
   273             if (std::equal(tag, tag + 3, 
"FEN")) {
   274                 std::string tmp{value.first, value.second};
   279             if (std::equal(tag, tag + 4, 
"Date")) {
   285             if (std::equal(tag, tag + 6, 
"Result"))
   286                 return parseTagResult(value);
   289             if (std::equal(tag, tag + 7, 
"UTCDate") &&
   296             if (std::equal(tag, tag + 9, 
"EventDate")) {
   300             if (std::equal(tag, tag + 9, 
"ScidFlags")) {
   302                                   std::distance(value.first, value.second));
   311             if (std::equal(tag, tag + 5, 
"White") && game.
GetWhiteElo() == 0) {
   315             } 
else if (std::equal(tag, tag + 5, 
"Black") &&
   323         str.assign(value.first, value.second);
   324         linenum_ += pgn::normalize<true>(str, 0);
   334     unsigned long long n_bytes = 0;
   335     unsigned long long n_lines = 0;
   336     unsigned long long n_games = 0;
   345         for (
auto& e : visitor.errors_) {
   346             log += 
"(game " + std::to_string(n_games);
   347             log += 
", line " + std::to_string(n_lines + e.first) + 
") ";
   351         n_lines += visitor.linenum_;
   353         if (visitor.nErrorsAllowed_ < 0) {
   354             log += 
"(game " + std::to_string(n_games);
   355             log += 
", line " + std::to_string(n_lines) + 
") ";
   356             log += 
"End of game, ignored the part after the last error.\n";
   382     if (!log.
logGame(parse.first, visitor))
   385     if (parse.first == inputLen && !parse.second &&
   392 #endif // idndef SCID_PGNPARSE_H bool visitPGN_TagPair(TView tag, TView value)
 
int setRating(colorT col, const char *ratingType, size_t ratingTypeLen, std::pair< const char *, const char *> rating)
 
bool pgnParseGame(const char *input, size_t inputLen, Game &game, PgnParseLog &log)
Convert PGN text into a SCID's Game object. 
 
std::pair< std::size_t, bool > parse_game(pgn_impl::InputMemory input, TVisitor &&parser)
Read a PGN game from memory, grouping characters in tokens and dispatching them to a PGN parser...
 
std::string & accessMoveComment()
 
bool visitPGN_EndOfLine()
 
std::string & accessTagValue(const char *tag, size_t tagLen)
 
errorT SetStartFen(const char *fenStr)
Setup the start position from a FEN string and remove all the moves. 
 
This class implements a PGN "visitor" that invokes the appropriate member functions of the associated...
 
const char * GetMoveComment() const
 
Split input into PGN tokens and dispatch them to a "visiting" parser. 
 
const resultT RESULT_Black
 
void SetEventDate(dateT date)
 
const errorT ERROR_CastlingAvailability
 
bool visitPGN_VariationStart()
 
bool visitPGN_inputUnexpectedPGNHeader()
 
bool visitPGN_Suffix(TView token)
 
dateT date_parsePGNTag(const char *str, size_t len)
Creates a dateT object from a PGN tag value string. 
 
void SetResult(resultT res)
 
const resultT RESULT_Draw
 
bool visitPGN_Escape(TView)
 
bool logGame(size_t nBytes, const PgnVisitor &visitor)
Format and store errors occurred while parsing a Game. 
 
byte game_parseNag(std::pair< const char *, const char *> strview)
 
resultT GetResult() const
 
const resultT RESULT_White
 
bool visitPGN_VariationEnd()
 
bool visitPGN_SANMove(TView tok)
 
Position * GetCurrentPos()
 
errorT ParseMove(simpleMoveT *sm, const char *str)
 
bool visitPGN_MoveNum(TView)
 
errorT MoveExitVariation()
 
std::size_t trim(TView &str)
Trim leading and trailing white spaces. 
 
bool visitPGN_Comment(TView comment)
 
ecoT eco_FromString(const char *ecoStr)
 
bool visitPGN_EPD(TView line)
 
bool visitPGN_ResultFinal(char resultCh)
 
errorT AddMove(const simpleMoveT *sm)
 
const resultT RESULT_None
 
std::size_t normalize(TString &str, std::size_t pos)
Normalize white spaces and converts Latin-1 chars to UTF-8 sequences. 
 
bool visitPGN_NAG(TView token)
 
void SetScidFlags(const char *s, size_t len)
 
bool visitPGN_Unknown(TView token)