| 50 |
50 |
| 51 const char* pgn_error_str(int code) { |
51 const char* pgn_error_str(int code) { |
| 52 return pgn_error_strings[code]; |
52 return pgn_error_strings[code]; |
| 53 } |
53 } |
| 54 |
54 |
| |
55 size_t pgn_error_pos; |
| |
56 |
| |
57 size_t pgn_error_position(void) { |
| |
58 return pgn_error_pos; |
| |
59 } |
| |
60 |
| 55 static const char *pgn_result(GameState *gamestate) { |
61 static const char *pgn_result(GameState *gamestate) { |
| 56 if (gamestate->stalemate || gamestate->remis) { |
62 if (gamestate->stalemate || gamestate->remis) { |
| 57 return "1/2-1/2"; |
63 return "1/2-1/2"; |
| 58 } else if (gamestate->wresign) { |
64 } else if (gamestate->wresign) { |
| 59 return "0-1"; |
65 return "0-1"; |
| 84 while (isspace(c = *(pgndata++))); |
93 while (isspace(c = *(pgndata++))); |
| 85 if (c == '1') { |
94 if (c == '1') { |
| 86 break; |
95 break; |
| 87 } |
96 } |
| 88 if (c != '[') { |
97 if (c != '[') { |
| 89 return pgn_error_missing_bracket; |
98 return(pgn_error_missing_bracket); |
| 90 } |
99 } |
| 91 while (isspace(c = *(pgndata++))); |
100 while (isspace(c = *(pgndata++))); |
| 92 i = 0; |
101 i = 0; |
| 93 do { |
102 do { |
| 94 tagkey[i++] = c; |
103 tagkey[i++] = c; |
| 95 } while (!isspace(c = *(pgndata++))); |
104 } while (!isspace(c = *(pgndata++))); |
| 96 tagkey[i] = '\0'; |
105 tagkey[i] = '\0'; |
| 97 while (isspace(c = *(pgndata++))); |
106 while (isspace(c = *(pgndata++))); |
| 98 if (c != '"') { |
107 if (c != '"') { |
| 99 return pgn_error_missing_quote; |
108 return(pgn_error_missing_quote); |
| 100 } |
109 } |
| 101 i = 0; |
110 i = 0; |
| 102 while ((c = *(pgndata++)) != '"') { |
111 while ((c = *(pgndata++)) != '"') { |
| 103 if (c == '\n' || c == 0) { |
112 if (c == '\n' || c == 0) { |
| 104 return pgn_error_missing_quote; |
113 return(pgn_error_missing_quote); |
| 105 } |
114 } |
| 106 tagvalue[i++] = c; |
115 tagvalue[i++] = c; |
| 107 } |
116 } |
| 108 tagvalue[i] = '\0'; |
117 tagvalue[i] = '\0'; |
| 109 if (*(pgndata++) != ']') { |
118 if (*(pgndata++) != ']') { |
| 110 return pgn_error_missing_bracket; |
119 return(pgn_error_missing_bracket); |
| 111 } |
120 } |
| 112 |
121 |
| 113 // TODO: read clock info |
122 // TODO: read clock info |
| 114 |
123 |
| 115 if (strcmp("Result", tagkey) == 0) { |
124 if (strcmp("Result", tagkey) == 0) { |
| 132 while (isspace(c = *(pgndata++))); |
141 while (isspace(c = *(pgndata++))); |
| 133 i = 0; |
142 i = 0; |
| 134 do { |
143 do { |
| 135 movestr[i++] = c; |
144 movestr[i++] = c; |
| 136 if (i >= 10) { |
145 if (i >= 10) { |
| 137 return pgn_error_move_syntax; |
146 return(pgn_error_move_syntax); |
| 138 } |
147 } |
| 139 } while (!isspace(c = *(pgndata++))); |
148 } while (!isspace(c = *(pgndata++))); |
| 140 movestr[i] = '\0'; |
149 movestr[i] = '\0'; |
| 141 if (eval_move(gamestate, movestr, &move, curcol) |
150 if (eval_move(gamestate, movestr, &move, curcol) |
| 142 != VALID_MOVE_SYNTAX) { |
151 != VALID_MOVE_SYNTAX) { |
| 143 return pgn_error_move_syntax; |
152 return(pgn_error_move_syntax); |
| 144 } |
153 } |
| 145 if (validate_move(gamestate, &move) != VALID_MOVE_SEMANTICS) { |
154 if (validate_move(gamestate, &move) != VALID_MOVE_SEMANTICS) { |
| 146 return pgn_error_move_semantics; |
155 return(pgn_error_move_semantics); |
| 147 } |
156 } |
| 148 apply_move(gamestate, &move); |
157 apply_move(gamestate, &move); |
| 149 |
158 |
| 150 /* skip spaces */ |
159 /* skip spaces */ |
| 151 while (isspace(c = *(pgndata++))); |
160 while (isspace(c = *(pgndata++))); |
| 178 if (c == '1') { |
187 if (c == '1') { |
| 179 gamestate->wresign = true; |
188 gamestate->wresign = true; |
| 180 } else if (c == '0') { |
189 } else if (c == '0') { |
| 181 gamestate->bresign = true; |
190 gamestate->bresign = true; |
| 182 } else { |
191 } else { |
| 183 return pgn_error_result_syntax; |
192 return(pgn_error_result_syntax); |
| 184 } |
193 } |
| 185 } |
194 } |
| 186 movetext_ends_with_result = true; |
195 movetext_ends_with_result = true; |
| 187 break; |
196 break; |
| 188 } else if (c == '/') { |
197 } else if (c == '/') { |
| 200 |
209 |
| 201 /* skip move number after black move */ |
210 /* skip move number after black move */ |
| 202 if (curcol == BLACK) { |
211 if (curcol == BLACK) { |
| 203 while (isdigit(c = *(pgndata++))); |
212 while (isdigit(c = *(pgndata++))); |
| 204 if (c != '.') { |
213 if (c != '.') { |
| 205 return pgn_error_missing_dot; |
214 return(pgn_error_missing_dot); |
| 206 } |
215 } |
| 207 } |
216 } |
| 208 curcol = opponent_color(curcol); |
217 curcol = opponent_color(curcol); |
| 209 } |
218 } |
| 210 |
219 |
| 211 /* sanity check result - if it was specified */ |
220 /* sanity check result - if it was specified */ |
| 212 if (movetext_ends_with_result && result[0]) { |
221 if (movetext_ends_with_result && result[0]) { |
| 213 if (strncmp(result, pgn_result(gamestate), 8) != 0) { |
222 if (strncmp(result, pgn_result(gamestate), 8) != 0) { |
| 214 fprintf(stderr, "Fuck it: %s\n", result); |
223 return(pgn_error_result_mismatch); |
| 215 return pgn_error_result_mismatch; |
224 } |
| 216 } |
225 } |
| 217 } |
226 |
| 218 |
227 return(pgn_no_error); |
| 219 return pgn_no_error; |
228 } |
| 220 } |
229 |
| |
230 #undef return |
| 221 |
231 |
| 222 int read_pgn(FILE *stream, GameState *gamestate) { |
232 int read_pgn(FILE *stream, GameState *gamestate) { |
| 223 fseek(stream, 0, SEEK_END); |
233 fseek(stream, 0, SEEK_END); |
| 224 long int size = ftell(stream); |
234 long int size = ftell(stream); |
| 225 fseek(stream, 0, SEEK_SET); |
235 fseek(stream, 0, SEEK_SET); |
| 226 char *data = malloc(size + 1); |
236 char *data = malloc(size + 1); |
| 227 memset(data, 0, size + 1); |
237 memset(data, 0, size + 1); |
| 228 size_t read = 0; |
238 size_t read = 0; |
| 229 do { |
239 do { |
| 230 size_t r = fread(data + read, 1, size - read, stream); |
240 size_t r = fread(data + read, 1, size - read, stream); |
| 231 if (r == 0) return pgn_error_unexpected_eof; |
241 if (r == 0) { |
| |
242 pgn_error_pos = read; |
| |
243 return pgn_error_unexpected_eof; |
| |
244 } |
| 232 read += r; |
245 read += r; |
| 233 } while (read < size); |
246 } while (read < size); |
| 234 int result = parse_pgn(data, gamestate); |
247 int result = parse_pgn(data, gamestate); |
| 235 free(data); |
248 free(data); |
| 236 return result; |
249 return result; |