30 #include "pgn.h" |
30 #include "pgn.h" |
31 #include <ctype.h> |
31 #include <ctype.h> |
32 #include <stdlib.h> |
32 #include <stdlib.h> |
33 #include <string.h> |
33 #include <string.h> |
34 |
34 |
|
35 enum { |
|
36 pgn_error_missing_quote = 1, |
|
37 pgn_error_missing_bracket, |
|
38 pgn_error_missing_dot, |
|
39 pgn_error_move_syntax, |
|
40 pgn_error_move_semantics |
|
41 }; |
|
42 |
|
43 static const char* pgn_error_strings[] = { |
|
44 "No Error.", |
|
45 "Tag values must be enclosed in double-quotes.", |
|
46 "Tags must be enclosed in square brackets: '[Key \"Value\"]'.", |
|
47 "Move numbers must be terminated with a dot (e.g. '13.' - not '13').", |
|
48 "Move is syntactically incorrect.", |
|
49 "Move is not valid according to chess rules." |
|
50 }; |
|
51 |
|
52 const char* pgn_error_str(int code) { |
|
53 return pgn_error_strings[code]; |
|
54 } |
|
55 |
35 int read_pgn(FILE* stream, GameState *gamestate, GameInfo *gameinfo) { |
56 int read_pgn(FILE* stream, GameState *gamestate, GameInfo *gameinfo) { |
36 int c, i; |
57 int c, i; |
37 |
58 |
38 char result[8]; |
59 char result[8]; |
39 |
60 |
47 if (c == '1') { |
68 if (c == '1') { |
48 readmoves = 1; |
69 readmoves = 1; |
49 break; |
70 break; |
50 } |
71 } |
51 if (c != '[') { |
72 if (c != '[') { |
52 return 1; |
73 return pgn_error_missing_bracket; |
53 } |
74 } |
54 while (isspace(c = fgetc(stream))); |
75 while (isspace(c = fgetc(stream))); |
55 i = 0; |
76 i = 0; |
56 do { |
77 do { |
57 tagkey[i++] = c; |
78 tagkey[i++] = c; |
58 } while (!isspace(c = fgetc(stream))); |
79 } while (!isspace(c = fgetc(stream))); |
59 tagkey[i] = '\0'; |
80 tagkey[i] = '\0'; |
60 while (isspace(c = fgetc(stream))); |
81 while (isspace(c = fgetc(stream))); |
61 if (c != '"') { |
82 if (c != '"') { |
62 return 1; |
83 return pgn_error_missing_quote; |
63 } |
84 } |
64 i = 0; |
85 i = 0; |
65 while ((c = fgetc(stream)) != '"') { |
86 while ((c = fgetc(stream)) != '"') { |
66 if (c == '\n') { |
87 if (c == '\n' || c == EOF) { |
67 return 1; |
88 return pgn_error_missing_quote; |
68 } |
89 } |
69 tagvalue[i++] = c; |
90 tagvalue[i++] = c; |
70 } |
91 } |
71 tagvalue[i] = '\0'; |
92 tagvalue[i] = '\0'; |
72 if (fgetc(stream) != ']') { |
93 if (fgetc(stream) != ']') { |
73 return 1; |
94 return pgn_error_missing_bracket; |
74 } |
95 } |
75 |
96 |
76 if (strcmp("Result", tagkey) == 0) { |
97 if (strcmp("Result", tagkey) == 0) { |
77 memcpy(result, tagvalue, 8); |
98 memcpy(result, tagvalue, 8); |
78 } |
99 } |
79 } |
100 } |
80 |
101 |
81 // read moves |
102 // read moves |
82 if (fgetc(stream) != '.') { |
103 if (fgetc(stream) != '.') { |
83 return 1; |
104 return pgn_error_missing_dot; |
84 } |
105 } |
85 |
106 |
86 char movestr[10]; |
107 char movestr[10]; |
87 Move move; |
108 Move move; |
88 uint8_t curcol = WHITE; |
109 uint8_t curcol = WHITE; |
98 } |
119 } |
99 } while (!isspace(c = fgetc(stream))); |
120 } while (!isspace(c = fgetc(stream))); |
100 movestr[i] = '\0'; |
121 movestr[i] = '\0'; |
101 if (eval_move(gamestate, movestr, &move, curcol) |
122 if (eval_move(gamestate, movestr, &move, curcol) |
102 != VALID_MOVE_SYNTAX) { |
123 != VALID_MOVE_SYNTAX) { |
103 return 1; |
124 return pgn_error_move_syntax; |
104 } |
125 } |
105 if (validate_move(gamestate, &move) != VALID_MOVE_SEMANTICS) { |
126 if (validate_move(gamestate, &move) != VALID_MOVE_SEMANTICS) { |
106 return 1; |
127 return pgn_error_move_semantics; |
107 } |
128 } |
108 apply_move(gamestate, &move); |
129 apply_move(gamestate, &move); |
109 |
130 |
110 // TODO: parse comments |
131 // TODO: parse comments |
111 while (isspace(c = fgetc(stream))); |
132 while (isspace(c = fgetc(stream))); |