src/chess/pgn.c

changeset 60
0c50aac49e55
parent 59
3fa1de896666
child 64
4eda5df55f86
equal deleted inserted replaced
59:3fa1de896666 60:0c50aac49e55
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)));
133 154
134 // skip move number after black move 155 // skip move number after black move
135 if (curcol == BLACK) { 156 if (curcol == BLACK) {
136 while (isdigit(c = fgetc(stream))); 157 while (isdigit(c = fgetc(stream)));
137 if (c != '.') { 158 if (c != '.') {
138 return 1; 159 return pgn_error_missing_dot;
139 } 160 }
140 } 161 }
141 curcol = opponent_color(curcol); 162 curcol = opponent_color(curcol);
142 } 163 }
143 164

mercurial