2014-01-07 02:19:07 +00:00
|
|
|
/* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
*
|
2013-07-07 21:14:29 +00:00
|
|
|
* Copyright (C) 2010-2013 Robert Ancell
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify it under
|
|
|
|
* the terms of the GNU General Public License as published by the Free Software
|
|
|
|
* Foundation, either version 2 of the License, or (at your option) any later
|
|
|
|
* version. See http://www.gnu.org/copyleft/gpl.html the full text of the
|
|
|
|
* license.
|
|
|
|
*/
|
|
|
|
|
2010-12-08 07:18:30 +00:00
|
|
|
private int str_index (string name)
|
|
|
|
{
|
|
|
|
if (name == "Event")
|
|
|
|
return 0;
|
|
|
|
else if (name == "Site")
|
|
|
|
return 1;
|
|
|
|
else if (name == "Date")
|
|
|
|
return 2;
|
|
|
|
else if (name == "Round")
|
|
|
|
return 3;
|
|
|
|
else if (name == "White")
|
|
|
|
return 4;
|
|
|
|
else if (name == "Black")
|
|
|
|
return 5;
|
|
|
|
else if (name == "Result")
|
|
|
|
return 6;
|
|
|
|
else
|
|
|
|
return 7;
|
|
|
|
}
|
|
|
|
|
|
|
|
private int compare_tag (string name0, string name1)
|
|
|
|
{
|
|
|
|
int str_index0 = str_index (name0);
|
|
|
|
int str_index1 = str_index (name1);
|
|
|
|
|
|
|
|
/* If both not in STR then just order alphabetically */
|
|
|
|
if (str_index0 == 7 && str_index1 == 7)
|
|
|
|
return strcmp (name0, name1);
|
|
|
|
else
|
|
|
|
return str_index0 - str_index1;
|
|
|
|
}
|
|
|
|
|
2011-01-01 02:42:03 +00:00
|
|
|
public errordomain PGNError
|
|
|
|
{
|
|
|
|
LOAD_ERROR
|
|
|
|
}
|
|
|
|
|
2014-06-24 13:14:59 +00:00
|
|
|
public class PGNGame : Object
|
2010-12-08 07:18:30 +00:00
|
|
|
{
|
2011-01-01 01:42:50 +00:00
|
|
|
public HashTable<string, string> tags;
|
|
|
|
public List<string> moves;
|
2010-12-08 07:18:30 +00:00
|
|
|
|
2011-01-01 03:24:41 +00:00
|
|
|
public static string RESULT_IN_PROGRESS = "*";
|
|
|
|
public static string RESULT_DRAW = "1/2-1/2";
|
|
|
|
public static string RESULT_WHITE = "1-0";
|
|
|
|
public static string RESULT_BLACK = "0-1";
|
|
|
|
|
2011-01-01 03:58:25 +00:00
|
|
|
public static string TERMINATE_ABANDONED = "abandoned";
|
|
|
|
public static string TERMINATE_ADJUDICATION = "adjudication";
|
|
|
|
public static string TERMINATE_DEATH = "death";
|
|
|
|
public static string TERMINATE_EMERGENCY = "emergency";
|
|
|
|
public static string TERMINATE_NORMAL = "normal";
|
|
|
|
public static string TERMINATE_RULES_INFRACTION = "rules infraction";
|
|
|
|
public static string TERMINATE_TIME_FORFEIT = "time forfeit";
|
|
|
|
public static string TERMINATE_UNTERMINATED = "unterminated";
|
|
|
|
|
2010-12-08 07:18:30 +00:00
|
|
|
public string event
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("Event"); }
|
|
|
|
set { tags.insert ("Event", value); }
|
|
|
|
}
|
|
|
|
public string site
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("Site"); }
|
|
|
|
set { tags.insert ("Site", value); }
|
|
|
|
}
|
|
|
|
public string date
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("Date"); }
|
|
|
|
set { tags.insert ("Date", value); }
|
|
|
|
}
|
2011-01-09 03:25:33 +00:00
|
|
|
public string time
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("Time"); }
|
|
|
|
set { tags.insert ("Time", value); }
|
|
|
|
}
|
2010-12-08 07:18:30 +00:00
|
|
|
public string round
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("Round"); }
|
|
|
|
set { tags.insert ("Round", value); }
|
|
|
|
}
|
|
|
|
public string white
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("White"); }
|
|
|
|
set { tags.insert ("White", value); }
|
|
|
|
}
|
|
|
|
public string black
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("Black"); }
|
|
|
|
set { tags.insert ("Black", value); }
|
|
|
|
}
|
|
|
|
public string result
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("Result"); }
|
|
|
|
set { tags.insert ("Result", value); }
|
|
|
|
}
|
2010-12-27 02:31:07 +00:00
|
|
|
public string? annotator
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("Annotator"); }
|
|
|
|
set { tags.insert ("Annotator", value); }
|
|
|
|
}
|
2011-01-09 03:25:33 +00:00
|
|
|
public string? time_control
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("TimeControl"); }
|
|
|
|
set { tags.insert ("TimeControl", value); }
|
|
|
|
}
|
2013-06-08 21:41:45 +00:00
|
|
|
public string? white_time_left
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("WhiteTimeLeft"); }
|
|
|
|
set { tags.insert ("WhiteTimeLeft", value); }
|
|
|
|
}
|
|
|
|
public string? black_time_left
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("BlackTimeLeft"); }
|
|
|
|
set { tags.insert ("BlackTimeLeft", value); }
|
|
|
|
}
|
2015-02-16 04:07:37 +00:00
|
|
|
public string? clock_type
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("X-GNOME-ClockType"); }
|
|
|
|
set { tags.insert ("X-GNOME-ClockType", value); }
|
|
|
|
}
|
|
|
|
public string? timer_increment
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("X-GNOME-TimerIncrement"); }
|
|
|
|
set { tags.insert ("X-GNOME-TimerIncrement", value); }
|
|
|
|
}
|
2010-12-27 01:47:46 +00:00
|
|
|
public bool set_up
|
|
|
|
{
|
|
|
|
get { string? v = tags.lookup ("SetUp"); return v != null && v == "1" ? true : false; }
|
|
|
|
set { tags.insert ("SetUp", value ? "1" : "0"); }
|
|
|
|
}
|
|
|
|
public string? fen
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("FEN"); }
|
2010-12-27 02:31:07 +00:00
|
|
|
set { tags.insert ("FEN", value); }
|
2010-12-27 01:47:46 +00:00
|
|
|
}
|
|
|
|
public string? termination
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("Termination"); }
|
|
|
|
set { tags.insert ("Termination", value); }
|
2011-01-09 03:25:33 +00:00
|
|
|
}
|
2013-06-08 22:08:45 +00:00
|
|
|
public string? white_ai
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("WhiteAI"); }
|
|
|
|
set { tags.insert ("WhiteAI", value); }
|
|
|
|
}
|
|
|
|
public string? white_level
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("WhiteLevel"); }
|
|
|
|
set { tags.insert ("WhiteLevel", value); }
|
|
|
|
}
|
|
|
|
public string? black_ai
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("BlackAI"); }
|
|
|
|
set { tags.insert ("BlackAI", value); }
|
|
|
|
}
|
|
|
|
public string? black_level
|
|
|
|
{
|
|
|
|
get { return tags.lookup ("BlackLevel"); }
|
|
|
|
set { tags.insert ("BlackLevel", value); }
|
|
|
|
}
|
2010-12-08 07:18:30 +00:00
|
|
|
|
|
|
|
public PGNGame ()
|
|
|
|
{
|
2011-01-01 01:42:50 +00:00
|
|
|
tags = new HashTable<string, string> (str_hash, str_equal);
|
2010-12-08 07:18:30 +00:00
|
|
|
tags.insert ("Event", "?");
|
|
|
|
tags.insert ("Site", "?");
|
|
|
|
tags.insert ("Date", "????.??.??");
|
|
|
|
tags.insert ("Round", "?");
|
|
|
|
tags.insert ("White", "?");
|
|
|
|
tags.insert ("Black", "?");
|
2011-01-01 03:24:41 +00:00
|
|
|
tags.insert ("Result", PGNGame.RESULT_IN_PROGRESS);
|
2010-12-08 07:18:30 +00:00
|
|
|
}
|
|
|
|
|
2011-07-01 10:58:03 +00:00
|
|
|
public string escape (string value)
|
2014-04-08 23:41:55 +00:00
|
|
|
{
|
2011-07-01 10:58:03 +00:00
|
|
|
var a = value.replace ("\\", "\\\\");
|
|
|
|
return a.replace ("\"", "\\\"");
|
|
|
|
}
|
|
|
|
|
2011-01-01 03:24:41 +00:00
|
|
|
public void write (File file) throws Error
|
2010-12-08 07:18:30 +00:00
|
|
|
{
|
2011-01-01 03:24:41 +00:00
|
|
|
var data = new StringBuilder ();
|
|
|
|
|
2010-12-08 07:18:30 +00:00
|
|
|
var keys = tags.get_keys ();
|
2011-01-01 01:42:50 +00:00
|
|
|
keys.sort ((CompareFunc) compare_tag);
|
2010-12-08 07:18:30 +00:00
|
|
|
foreach (var key in keys)
|
2011-07-01 10:58:03 +00:00
|
|
|
data.append ("[%s \"%s\"]\n".printf (key, escape (tags.lookup (key))));
|
2011-01-01 03:24:41 +00:00
|
|
|
data.append ("\n");
|
2010-12-08 07:18:30 +00:00
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
foreach (string move in moves)
|
|
|
|
{
|
|
|
|
if (i % 2 == 0)
|
2011-01-01 03:24:41 +00:00
|
|
|
data.append ("%d. ".printf (i / 2 + 1));
|
|
|
|
data.append (move);
|
|
|
|
data.append (" ");
|
2010-12-08 07:18:30 +00:00
|
|
|
i++;
|
|
|
|
}
|
2011-01-01 03:24:41 +00:00
|
|
|
data.append (result);
|
|
|
|
data.append ("\n");
|
2010-12-08 07:18:30 +00:00
|
|
|
|
2012-02-05 06:05:02 +00:00
|
|
|
file.replace_contents (data.str.data, null, false, FileCreateFlags.NONE, null);
|
2010-12-08 07:18:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum State
|
|
|
|
{
|
2011-02-22 01:34:19 +00:00
|
|
|
TAGS,
|
|
|
|
MOVE_TEXT,
|
2010-12-08 07:18:30 +00:00
|
|
|
LINE_COMMENT,
|
|
|
|
BRACE_COMMENT,
|
|
|
|
TAG_START,
|
|
|
|
TAG_NAME,
|
|
|
|
PRE_TAG_VALUE,
|
|
|
|
TAG_VALUE,
|
|
|
|
POST_TAG_VALUE,
|
|
|
|
SYMBOL,
|
2011-02-22 01:34:19 +00:00
|
|
|
PERIOD,
|
2010-12-08 07:18:30 +00:00
|
|
|
NAG,
|
|
|
|
ERROR
|
|
|
|
}
|
|
|
|
|
2014-06-24 13:14:59 +00:00
|
|
|
public class PGN : Object
|
2010-12-08 07:18:30 +00:00
|
|
|
{
|
2011-01-01 01:42:50 +00:00
|
|
|
public List<PGNGame> games;
|
2015-03-14 15:34:16 +00:00
|
|
|
private void insert_tag (PGNGame game, string tag_name, string tag_value)
|
|
|
|
{
|
|
|
|
switch (tag_name)
|
|
|
|
{
|
2015-03-29 15:14:53 +00:00
|
|
|
case "WhiteTimeLeft":
|
|
|
|
if (int64.try_parse (tag_value) == false)
|
2015-04-04 13:16:47 +00:00
|
|
|
warning (_("Invalid %s : %s in PGN, setting timer to infinity."), tag_name, tag_value);
|
2015-03-29 15:14:53 +00:00
|
|
|
else
|
|
|
|
game.tags.insert (tag_name, tag_value);
|
|
|
|
break;
|
|
|
|
case "BlackTimeLeft":
|
|
|
|
if (int64.try_parse (tag_value) == false)
|
2015-04-04 13:16:47 +00:00
|
|
|
warning (_("Invalid %s : %s in PGN, setting timer to infinity."), tag_name, tag_value);
|
2015-03-29 15:14:53 +00:00
|
|
|
else
|
|
|
|
game.tags.insert (tag_name, tag_value);
|
|
|
|
break;
|
|
|
|
case "TimeControl":
|
|
|
|
if (int64.try_parse (tag_value) == true)
|
|
|
|
{
|
|
|
|
if (game.tags["WhiteTimeLeft"] != null && game.tags["BlackTimeLeft"] != null)
|
|
|
|
game.tags.insert (tag_name, tag_value);
|
|
|
|
}
|
|
|
|
else
|
2015-04-04 13:16:47 +00:00
|
|
|
warning (_("Invalid %s : %s in PGN, setting timer to infinity."), tag_name, tag_value);
|
2015-03-29 15:14:53 +00:00
|
|
|
break;
|
2015-03-14 15:34:16 +00:00
|
|
|
case "X-GNOME-ClockType":
|
|
|
|
if (ClockType.string_to_enum (tag_value) == ClockType.INVALID)
|
|
|
|
{
|
2015-04-04 13:16:47 +00:00
|
|
|
warning (_("Invalid clock type in PGN: %s, using a simple clock."), tag_value);
|
2015-03-29 15:14:53 +00:00
|
|
|
game.tags.insert (tag_name, "simple");
|
2015-03-14 15:34:16 +00:00
|
|
|
}
|
|
|
|
break;
|
2015-03-29 15:14:53 +00:00
|
|
|
case "X-GNOME-TimerIncrement":
|
|
|
|
if (int64.try_parse (tag_value) == false)
|
|
|
|
{
|
2015-04-04 13:16:47 +00:00
|
|
|
warning (_("Invalid timer increment in PGN: %s, using a simple clock."), tag_value);
|
2015-03-29 15:14:53 +00:00
|
|
|
game.tags["X-GNOME-ClockType"] = "simple";
|
|
|
|
game.tags.insert (tag_name, "0");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
game.tags.insert (tag_name, tag_value);
|
|
|
|
break;
|
2015-03-14 15:34:16 +00:00
|
|
|
}
|
|
|
|
}
|
2010-12-08 07:18:30 +00:00
|
|
|
|
2011-02-22 01:34:19 +00:00
|
|
|
public PGN.from_string (string data) throws PGNError
|
2010-12-08 07:18:30 +00:00
|
|
|
{
|
|
|
|
// FIXME: Feed through newline at end to make sure parsing complete
|
2011-02-22 01:34:19 +00:00
|
|
|
|
|
|
|
State state = State.TAGS, home_state = State.TAGS;
|
2010-12-08 07:18:30 +00:00
|
|
|
PGNGame game = new PGNGame ();
|
|
|
|
bool in_escape = false;
|
|
|
|
size_t token_start = 0, line_offset = 0;
|
|
|
|
string tag_name = "";
|
|
|
|
StringBuilder tag_value = new StringBuilder ();
|
|
|
|
int line = 1;
|
|
|
|
int rav_level = 0;
|
2011-02-22 01:34:19 +00:00
|
|
|
for (size_t offset = 0; offset <= data.length; offset++)
|
2010-12-08 07:18:30 +00:00
|
|
|
{
|
2011-02-22 01:34:19 +00:00
|
|
|
unichar c = data[(long) offset];
|
|
|
|
|
2010-12-08 07:18:30 +00:00
|
|
|
if (c == '\n')
|
|
|
|
{
|
|
|
|
line++;
|
|
|
|
line_offset = offset + 1;
|
|
|
|
}
|
2014-04-08 23:41:55 +00:00
|
|
|
|
2010-12-08 07:18:30 +00:00
|
|
|
switch (state)
|
|
|
|
{
|
2011-02-22 01:34:19 +00:00
|
|
|
case State.TAGS:
|
|
|
|
home_state = State.TAGS;
|
2015-02-15 03:36:44 +00:00
|
|
|
if (c == ';')
|
2010-12-08 07:18:30 +00:00
|
|
|
state = State.LINE_COMMENT;
|
|
|
|
else if (c == '{')
|
|
|
|
state = State.BRACE_COMMENT;
|
|
|
|
else if (c == '[')
|
|
|
|
state = State.TAG_START;
|
2015-02-15 03:36:44 +00:00
|
|
|
else if (!c.isspace ())
|
2011-02-22 01:34:19 +00:00
|
|
|
{
|
|
|
|
offset--;
|
|
|
|
state = State.MOVE_TEXT;
|
|
|
|
continue;
|
2010-12-08 07:18:30 +00:00
|
|
|
}
|
2011-02-22 01:34:19 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case State.MOVE_TEXT:
|
|
|
|
home_state = State.MOVE_TEXT;
|
2015-02-15 03:36:44 +00:00
|
|
|
if (c == ';')
|
2011-02-22 01:34:19 +00:00
|
|
|
state = State.LINE_COMMENT;
|
|
|
|
else if (c == '{')
|
|
|
|
state = State.BRACE_COMMENT;
|
|
|
|
else if (c == '*')
|
2010-12-08 07:18:30 +00:00
|
|
|
{
|
|
|
|
if (rav_level == 0)
|
|
|
|
{
|
2011-01-01 03:24:41 +00:00
|
|
|
game.result = PGNGame.RESULT_IN_PROGRESS;
|
2010-12-08 07:18:30 +00:00
|
|
|
games.append (game);
|
|
|
|
game = new PGNGame ();
|
2011-02-22 01:34:19 +00:00
|
|
|
state = State.TAGS;
|
2010-12-08 07:18:30 +00:00
|
|
|
}
|
|
|
|
}
|
2011-02-22 01:34:19 +00:00
|
|
|
else if (c == '.')
|
|
|
|
{
|
|
|
|
offset--;
|
|
|
|
state = State.PERIOD;
|
|
|
|
}
|
|
|
|
else if (c.isalnum ())
|
2010-12-08 07:18:30 +00:00
|
|
|
{
|
|
|
|
token_start = offset;
|
|
|
|
state = State.SYMBOL;
|
|
|
|
}
|
2011-02-22 01:34:19 +00:00
|
|
|
else if (c == '$')
|
2010-12-08 07:18:30 +00:00
|
|
|
{
|
|
|
|
token_start = offset + 1;
|
|
|
|
state = State.NAG;
|
|
|
|
}
|
2011-02-22 01:34:19 +00:00
|
|
|
else if (c == '(')
|
2010-12-08 07:18:30 +00:00
|
|
|
{
|
|
|
|
rav_level++;
|
|
|
|
continue;
|
|
|
|
}
|
2011-02-22 01:34:19 +00:00
|
|
|
else if (c == ')')
|
2010-12-08 07:18:30 +00:00
|
|
|
{
|
|
|
|
if (rav_level == 0)
|
|
|
|
state = State.ERROR;
|
|
|
|
else
|
|
|
|
rav_level--;
|
|
|
|
}
|
2015-02-15 05:14:49 +00:00
|
|
|
else if (!c.isspace ())
|
2010-12-08 07:18:30 +00:00
|
|
|
state = State.ERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case State.LINE_COMMENT:
|
|
|
|
if (c == '\n')
|
2011-02-22 01:34:19 +00:00
|
|
|
state = home_state;
|
2010-12-08 07:18:30 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case State.BRACE_COMMENT:
|
|
|
|
if (c == '}')
|
2011-02-22 01:34:19 +00:00
|
|
|
state = home_state;
|
2010-12-08 07:18:30 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case State.TAG_START:
|
|
|
|
if (c.isspace ())
|
|
|
|
continue;
|
2015-02-19 15:19:36 +00:00
|
|
|
else if (c.isalnum ())
|
2010-12-08 07:18:30 +00:00
|
|
|
{
|
|
|
|
token_start = offset;
|
|
|
|
state = State.TAG_NAME;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
state = State.ERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case State.TAG_NAME:
|
|
|
|
if (c.isspace ())
|
|
|
|
{
|
2015-02-19 15:19:36 +00:00
|
|
|
tag_name = data[(long) token_start:(long) offset];
|
2010-12-08 07:18:30 +00:00
|
|
|
state = State.PRE_TAG_VALUE;
|
|
|
|
}
|
2015-02-19 15:19:36 +00:00
|
|
|
else if (c.isalnum () || c == '_' || c == '+' || c == '#' || c == '=' || c == ':' || c == '-')
|
2010-12-08 07:18:30 +00:00
|
|
|
continue;
|
|
|
|
else
|
|
|
|
state = State.ERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case State.PRE_TAG_VALUE:
|
|
|
|
if (c.isspace ())
|
|
|
|
continue;
|
|
|
|
else if (c == '"')
|
|
|
|
{
|
|
|
|
state = State.TAG_VALUE;
|
|
|
|
tag_value.erase ();
|
|
|
|
in_escape = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
state = State.ERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case State.TAG_VALUE:
|
|
|
|
if (c == '\\' && !in_escape)
|
|
|
|
in_escape = true;
|
|
|
|
else if (c == '"' && !in_escape)
|
|
|
|
state = State.POST_TAG_VALUE;
|
|
|
|
else if (c.isprint ())
|
|
|
|
{
|
|
|
|
tag_value.append_unichar (c);
|
|
|
|
in_escape = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
state = State.ERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case State.POST_TAG_VALUE:
|
|
|
|
if (c.isspace ())
|
|
|
|
continue;
|
|
|
|
else if (c == ']')
|
|
|
|
{
|
2015-03-14 15:34:16 +00:00
|
|
|
insert_tag (game, tag_name, tag_value.str);
|
2011-02-22 01:34:19 +00:00
|
|
|
state = State.TAGS;
|
2010-12-08 07:18:30 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
state = State.ERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case State.SYMBOL:
|
|
|
|
/* NOTE: '/' not in spec but required for 1/2-1/2 symbol */
|
|
|
|
if (c.isalnum () || c == '_' || c == '+' || c == '#' || c == '=' || c == ':' || c == '-' || c == '/')
|
|
|
|
continue;
|
|
|
|
else
|
|
|
|
{
|
2015-02-19 15:19:36 +00:00
|
|
|
string symbol = data[(long) token_start:(long) offset];
|
2010-12-08 07:18:30 +00:00
|
|
|
|
|
|
|
bool is_number = true;
|
|
|
|
for (int i = 0; i < symbol.length; i++)
|
|
|
|
if (!symbol[i].isdigit ())
|
|
|
|
is_number = false;
|
|
|
|
|
2011-02-22 01:34:19 +00:00
|
|
|
state = State.MOVE_TEXT;
|
|
|
|
offset--;
|
|
|
|
|
2010-12-08 07:18:30 +00:00
|
|
|
/* Game termination markers */
|
2011-01-01 03:24:41 +00:00
|
|
|
if (symbol == PGNGame.RESULT_DRAW || symbol == PGNGame.RESULT_WHITE || symbol == PGNGame.RESULT_BLACK)
|
2010-12-08 07:18:30 +00:00
|
|
|
{
|
|
|
|
if (rav_level == 0)
|
|
|
|
{
|
|
|
|
game.result = symbol;
|
|
|
|
games.append (game);
|
|
|
|
game = new PGNGame ();
|
2011-02-22 01:34:19 +00:00
|
|
|
state = State.TAGS;
|
2010-12-08 07:18:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!is_number)
|
|
|
|
{
|
|
|
|
if (rav_level == 0)
|
|
|
|
game.moves.append (symbol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2011-02-22 01:34:19 +00:00
|
|
|
case State.PERIOD:
|
|
|
|
/* FIXME: Should check these move carefully, e.g. "1. e2" */
|
|
|
|
state = State.MOVE_TEXT;
|
|
|
|
break;
|
|
|
|
|
2010-12-08 07:18:30 +00:00
|
|
|
case State.NAG:
|
|
|
|
if (c.isdigit ())
|
|
|
|
continue;
|
|
|
|
else
|
|
|
|
{
|
2011-02-22 01:34:19 +00:00
|
|
|
state = State.MOVE_TEXT;
|
2010-12-08 07:18:30 +00:00
|
|
|
offset--;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case State.ERROR:
|
|
|
|
size_t char_offset = offset - line_offset - 1;
|
2011-02-22 01:34:19 +00:00
|
|
|
stderr.printf ("%d.%d: error: Unexpected character\n", line, (int) (char_offset + 1));
|
2015-02-19 15:19:36 +00:00
|
|
|
stderr.printf ("%s\n", data[(long) line_offset:(long) offset]);
|
2010-12-08 07:18:30 +00:00
|
|
|
for (int i = 0; i < char_offset; i++)
|
|
|
|
stderr.printf (" ");
|
|
|
|
stderr.printf ("^\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2011-01-01 02:42:03 +00:00
|
|
|
|
2011-02-22 01:34:19 +00:00
|
|
|
if (game.moves.length () > 0 || game.tags.size () > 0)
|
|
|
|
games.append (game);
|
|
|
|
|
2011-01-01 02:42:03 +00:00
|
|
|
/* Must have at least one game */
|
|
|
|
if (games == null)
|
2015-02-19 15:19:36 +00:00
|
|
|
throw new PGNError.LOAD_ERROR ("No games in PGN file");
|
2011-07-01 10:58:45 +00:00
|
|
|
}
|
2011-02-22 01:34:19 +00:00
|
|
|
|
|
|
|
public PGN.from_file (File file) throws Error
|
|
|
|
{
|
2011-07-01 10:58:45 +00:00
|
|
|
uint8[] contents;
|
2012-02-03 16:00:37 +00:00
|
|
|
file.load_contents (null, out contents, null);
|
2011-07-01 10:58:45 +00:00
|
|
|
this.from_string ((string) contents);
|
2010-12-08 07:18:30 +00:00
|
|
|
}
|
2012-02-03 16:00:37 +00:00
|
|
|
}
|