Subversion Repositories Games.Chess Giants

Rev

Rev 66 | Rev 69 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 66 Rev 68
Line 12... Line 12...
12
      { \
12
      { \
13
         (dest)[char_index] = 0; \
13
         (dest)[char_index] = 0; \
14
         break; \
14
         break; \
15
      } \
15
      } \
16
}
16
}
-
 
17
 
-
 
18
 
-
 
19
// global variables used in this module only
-
 
20
static char *pgnfile_data = NULL; // mallocated
-
 
21
static size_t pgnfile_size = 0;
17
 
22
 
18
 
23
 
19
// prototypes of local functions
24
// prototypes of local functions
20
static void PGNFile_GameList_Init (int entry_count);
25
static void PGNFile_GameList_Init (int entry_count);
21
static void PGNFile_GameList_Shutdown (void);
26
static void PGNFile_GameList_Shutdown (void);
Line 25... Line 30...
25
bool PGNFile_Load (const wchar_t *pgnfile_pathname)
30
bool PGNFile_Load (const wchar_t *pgnfile_pathname)
26
{
31
{
27
   // this function loads a PGN file and builds the game databases of the games described in this file
32
   // this function loads a PGN file and builds the game databases of the games described in this file
28
 
33
 
29
   char line_buffer[256]; // PGN files have 256 chars max per line by design
34
   char line_buffer[256]; // PGN files have 256 chars max per line by design
30
   char *file_data; // mallocated
-
 
31
   char *buffer;
35
   char *buffer;
32
   int file_size;
-
 
33
   int file_index;
36
   int file_index;
34
   int char_index;
37
   int char_index;
35
   int entry_count;
38
   int entry_count;
36
   FILE *fp;
39
   FILE *fp;
37
   size_t converted_count; // used by the STRING_TO_CHAR macro
40
   size_t converted_count; // used by the STRING_TO_CHAR macro
Line 41... Line 44...
41
   if (fp == NULL)
44
   if (fp == NULL)
42
      return (false); // on error, cancel
45
      return (false); // on error, cancel
43
 
46
 
44
   // get file length
47
   // get file length
45
   fseek (fp, 0, SEEK_END);
48
   fseek (fp, 0, SEEK_END);
46
   file_size = ftell (fp);
49
   pgnfile_size = ftell (fp);
47
   fseek (fp, 0, SEEK_SET);
50
   fseek (fp, 0, SEEK_SET);
48
 
51
 
49
   // mallocate space for it and read it all at once
52
   // mallocate space for it and read it all at once
50
   file_data = (char *) SAFE_malloc (file_size, sizeof (char), false);
53
   pgnfile_data = (char *) SAFE_realloc (pgnfile_data, 0, pgnfile_size, sizeof (char), false);
51
   fread (file_data, file_size, 1, fp);
54
   fread (pgnfile_data, pgnfile_size, 1, fp);
52
   fclose (fp); // we no longer need the file, so close it
55
   fclose (fp); // we no longer need the file, so close it
53
 
56
 
54
   // now the file is fully loaded in memory
57
   // now the file is fully loaded in memory
55
 
58
 
56
   // read line per line and count the number of games
59
   // read line per line and count the number of games
57
   buffer = file_data;
60
   buffer = pgnfile_data;
58
   entry_count = 0;
61
   entry_count = 0;
59
   while ((buffer = sgets (line_buffer, sizeof (line_buffer), buffer)) != NULL)
62
   while ((buffer = sgets (line_buffer, sizeof (line_buffer), buffer)) != NULL)
60
      if (strncmp (line_buffer, "[Event \"", 8) == 0)
63
      if (strncmp (line_buffer, "[Event \"", 8) == 0)
61
         entry_count++; // we know now one game more
64
         entry_count++; // we know now one game more
62
 
65
 
63
   // now prepare the games database for "entry_count" games
66
   // now prepare the games database for "entry_count" games
64
   PGNFile_GameList_Init (entry_count);
67
   PGNFile_GameList_Init (entry_count);
65
 
68
 
66
   // read line per line
69
   // read line per line
67
   buffer = file_data;
70
   buffer = pgnfile_data;
68
   entry_count = 0;
71
   entry_count = 0;
69
   file_index = 0;
72
   file_index = 0;
70
   while ((buffer = sgets (line_buffer, sizeof (line_buffer), buffer)) != NULL)
73
   while ((buffer = sgets (line_buffer, sizeof (line_buffer), buffer)) != NULL)
71
   {
74
   {
72
      // is it a new game ?
75
      // is it a new game ?
Line 108... Line 111...
108
         // else is it the beginning of a game ?
111
         // else is it the beginning of a game ?
109
         else if (strncmp (line_buffer, "1.", 2) == 0)
112
         else if (strncmp (line_buffer, "1.", 2) == 0)
110
            games[entry_count - 1].gamedata_start = file_index; // remember where this game starts
113
            games[entry_count - 1].gamedata_start = file_index; // remember where this game starts
111
      }
114
      }
112
 
115
 
113
      file_index = buffer - file_data; // save current file pointer index
116
      file_index = buffer - pgnfile_data; // save current file pointer index
114
   }
117
   }
115
 
-
 
116
   // we no longer need the file data space, so free it
-
 
117
   SAFE_free ((void **) &file_data);
-
 
118
 
118
 
119
   return (true); // finished, return TRUE
119
   return (true); // finished, return TRUE
120
}
120
}
121
 
121
 
122
 
122
 
Line 125... Line 125...
125
   // this function loads and parses a game data in a PGN file. If the selected game is NULL, it means that
125
   // this function loads and parses a game data in a PGN file. If the selected game is NULL, it means that
126
   // the user didn't want to chose any game at all, so just free the games list and return a success value.
126
   // the user didn't want to chose any game at all, so just free the games list and return a success value.
127
 
127
 
128
   static wchar_t pgn_comment[65536]; // declared static so as not to reallocate it
128
   static wchar_t pgn_comment[65536]; // declared static so as not to reallocate it
129
 
129
 
130
   char *file_data; // mallocated
-
 
131
   boardmove_t new_move;
130
   boardmove_t new_move;
132
   int file_size;
-
 
133
   int length;
131
   int length;
134
   int char_index;
132
   int char_index;
135
   int fieldstart;
133
   int fieldstart;
136
   int fieldstop;
134
   int fieldstop;
137
   int variation_depth;
135
   int variation_depth;
138
   char movenumber_string[8];
136
   char movenumber_string[8];
139
   FILE *fp;
-
 
140
 
137
 
141
   // did we chose NO game ?
138
   // did we chose NO game ?
142
   if (game == NULL)
139
   if (game == NULL)
143
   {
140
   {
144
      PGNFile_GameList_Shutdown (); // free the games list
141
      PGNFile_GameList_Shutdown (); // free the games list
-
 
142
      SAFE_free ((void **) &pgnfile_data); // free the file data space
145
      return (true); // return success as there's nothing to load
143
      return (true); // return success as there's nothing to load
146
   }
144
   }
147
 
-
 
148
   // try to open file for reading in BINARY mode so as NOT to convert end of lines
-
 
149
   _wfopen_s (&fp, pgnfile_pathname, L"rb");
-
 
150
   if (fp == NULL)
-
 
151
   {
-
 
152
      PGNFile_GameList_Shutdown (); // free the games list
-
 
153
      return (false); // on error, cancel
-
 
154
   }
-
 
155
 
-
 
156
   // get file length
-
 
157
   fseek (fp, 0, SEEK_END);
-
 
158
   file_size = ftell (fp);
-
 
159
   fseek (fp, 0, SEEK_SET);
-
 
160
 
-
 
161
   // mallocate space for it and read it all at once
-
 
162
   file_data = (char *) SAFE_malloc (file_size, sizeof (char), false);
-
 
163
   fread (file_data, file_size, 1, fp);
-
 
164
   fclose (fp); // we no longer need the file, so close it
-
 
165
 
-
 
166
   // now the file is fully loaded in memory
-
 
167
 
145
 
168
   // reset the board (but NOT the players, just their view angles)
146
   // reset the board (but NOT the players, just their view angles)
169
   Board_Reset (board, game->fen_str);
147
   Board_Reset (board, game->fen_str);
170
   animation_endtime = current_time + 2.0f; // HACK: this sorta prevents the "load file" dialog box trailing clicks to be misinterpreted
148
   animation_endtime = current_time + 2.0f; // HACK: this sorta prevents the "load file" dialog box trailing clicks to be misinterpreted
171
 
149
 
Line 181... Line 159...
181
   {
159
   {
182
      // build the move number string
160
      // build the move number string
183
      sprintf_s (movenumber_string, sizeof (movenumber_string), "%d.", 1 + board->move_count / 2);
161
      sprintf_s (movenumber_string, sizeof (movenumber_string), "%d.", 1 + board->move_count / 2);
184
 
162
 
185
      // is it a space ?
163
      // is it a space ?
186
      if (isspace (file_data[char_index]))
164
      if (isspace (pgnfile_data[char_index]))
187
      {
165
      {
188
         char_index++; // if so, skip it
166
         char_index++; // if so, skip it
189
         continue; // and proceed to the next data
167
         continue; // and proceed to the next data
190
      }
168
      }
191
 
169
 
192
      // else is what we're reading a move number ?
170
      // else is what we're reading a move number ?
193
      else if (strncmp (&file_data[char_index], movenumber_string, strlen (movenumber_string)) == 0)
171
      else if (strncmp (&pgnfile_data[char_index], movenumber_string, strlen (movenumber_string)) == 0)
194
      {
172
      {
195
         char_index += strlen (movenumber_string); // if so, skip it
173
         char_index += strlen (movenumber_string); // if so, skip it
196
         continue; // and proceed to the next data
174
         continue; // and proceed to the next data
197
      }
175
      }
198
 
176
 
199
      // else is it a dot ?
177
      // else is it a dot ?
200
      else if (file_data[char_index] == '.')
178
      else if (pgnfile_data[char_index] == '.')
201
      {
179
      {
202
         char_index++; // if so, skip it
180
         char_index++; // if so, skip it
203
         continue; // and proceed to the next data
181
         continue; // and proceed to the next data
204
      }
182
      }
205
 
183
 
206
      // else is it an en passant notification ?
184
      // else is it an en passant notification ?
207
      else if (strncmp (&file_data[char_index], "e.p.", 4) == 0)
185
      else if (strncmp (&pgnfile_data[char_index], "e.p.", 4) == 0)
208
      {
186
      {
209
         char_index += 4; // this notification is superfluous, skip it
187
         char_index += 4; // this notification is superfluous, skip it
210
         continue; // and proceed to the next data
188
         continue; // and proceed to the next data
211
      }
189
      }
212
 
190
 
213
      // else is it a comment ?
191
      // else is it a comment ?
214
      else if (file_data[char_index] == '{')
192
      else if (pgnfile_data[char_index] == '{')
215
      {
193
      {
216
         fieldstart = char_index + 1; // skip the leading brace
194
         fieldstart = char_index + 1; // skip the leading brace
217
 
195
 
218
         while ((fieldstart < file_size) && isspace (file_data[fieldstart]))
196
         while ((fieldstart < (int) pgnfile_size) && isspace (pgnfile_data[fieldstart]))
219
            fieldstart++; // skip any leading spaces
197
            fieldstart++; // skip any leading spaces
220
 
198
 
221
         // move through all the other characters...
199
         // move through all the other characters...
222
         for (fieldstop = fieldstart; fieldstop < file_size; fieldstop++)
200
         for (fieldstop = fieldstart; fieldstop < (int) pgnfile_size; fieldstop++)
223
            if (file_data[fieldstop] == '}')
201
            if (pgnfile_data[fieldstop] == '}')
224
               break; // and stop at the first closing brace we find
202
               break; // and stop at the first closing brace we find
225
 
203
 
226
         char_index = fieldstop + 1; // remember where to continue reading (that is, after the closing brace)
204
         char_index = fieldstop + 1; // remember where to continue reading (that is, after the closing brace)
227
 
205
 
228
         while ((fieldstop > 0) && isspace (file_data[fieldstop]))
206
         while ((fieldstop > 0) && isspace (pgnfile_data[fieldstop]))
229
            fieldstop--; // chop off any trailing spaces
207
            fieldstop--; // chop off any trailing spaces
230
 
208
 
231
         file_data[fieldstop] = 0; // break the string at this location
209
         pgnfile_data[fieldstop] = 0; // break the string at this location
232
 
210
 
233
         // now copy out the commentary by appending it to the one we know already
211
         // now copy out the commentary by appending it to the one we know already
234
         if (pgn_comment[0] != 0)
212
         if (pgn_comment[0] != 0)
235
            wcscat_s (pgn_comment, WCHAR_SIZEOF (pgn_comment), L" ");
213
            wcscat_s (pgn_comment, WCHAR_SIZEOF (pgn_comment), L" ");
236
         length = wcslen (pgn_comment);
214
         length = wcslen (pgn_comment);
237
         ConvertToWideChar (&pgn_comment[length], WCHAR_SIZEOF (pgn_comment) - length, &file_data[fieldstart]);
215
         ConvertToWideChar (&pgn_comment[length], WCHAR_SIZEOF (pgn_comment) - length, &pgnfile_data[fieldstart]);
238
         ConvertCRLFsToSingleSpaces (pgn_comment); // linearize string
216
         ConvertCRLFsToSingleSpaces (pgn_comment); // linearize string
239
 
217
 
240
         continue; // and proceed to the next data
218
         continue; // and proceed to the next data
241
      }
219
      }
242
 
220
 
243
      // else is it a numeric annotation glyph ? if so, just ignore it (FIXME: better support this)
221
      // else is it a numeric annotation glyph ? if so, just ignore it (FIXME: better support this)
244
      else if (file_data[char_index] == '$')
222
      else if (pgnfile_data[char_index] == '$')
245
      {
223
      {
246
         while ((char_index < file_size) && !isspace (file_data[char_index]))
224
         while ((char_index < (int) pgnfile_size) && !isspace (pgnfile_data[char_index]))
247
            char_index++; // figure out where it stops
225
            char_index++; // figure out where it stops
248
         while ((char_index < file_size) && isspace (file_data[char_index]))
226
         while ((char_index < (int) pgnfile_size) && isspace (pgnfile_data[char_index]))
249
            char_index++; // figure out where the next word starts
227
            char_index++; // figure out where the next word starts
250
 
228
 
251
         continue; // and proceed to the next data
229
         continue; // and proceed to the next data
252
      }
230
      }
253
 
231
 
254
      // else is it a variation ? if so, just ignore it (FIXME: better support this)
232
      // else is it a variation ? if so, just ignore it (FIXME: better support this)
255
      else if (file_data[char_index] == '(')
233
      else if (pgnfile_data[char_index] == '(')
256
      {
234
      {
257
         variation_depth = 1;
235
         variation_depth = 1;
258
         while ((char_index < file_size) && (variation_depth != 0))
236
         while ((char_index < (int) pgnfile_size) && (variation_depth != 0))
259
         {
237
         {
260
            char_index++; // move through file data and cope with nested variations
238
            char_index++; // move through file data and cope with nested variations
261
            if      (file_data[char_index] == '(') variation_depth++;
239
            if      (pgnfile_data[char_index] == '(') variation_depth++;
262
            else if (file_data[char_index] == ')') variation_depth--;
240
            else if (pgnfile_data[char_index] == ')') variation_depth--;
263
         }
241
         }
264
         char_index++; // skip the closing parenthese
242
         char_index++; // skip the closing parenthese
265
         while ((char_index < file_size) && isspace (file_data[char_index]))
243
         while ((char_index < (int) pgnfile_size) && isspace (pgnfile_data[char_index]))
266
            char_index++; // figure out where the next word starts
244
            char_index++; // figure out where the next word starts
267
 
245
 
268
         continue; // and proceed to the next data
246
         continue; // and proceed to the next data
269
      }
247
      }
270
 
248
 
271
      // else is it a game result ?
249
      // else is it a game result ?
272
      else if ((strncmp (&file_data[char_index], "1/2-1/2", 7) == 0)
250
      else if ((strncmp (&pgnfile_data[char_index], "1/2-1/2", 7) == 0)
273
               || (strncmp (&file_data[char_index], "1-0", 3) == 0)
251
               || (strncmp (&pgnfile_data[char_index], "1-0", 3) == 0)
274
               || (strncmp (&file_data[char_index], "0-1", 3) == 0)
252
               || (strncmp (&pgnfile_data[char_index], "0-1", 3) == 0)
275
               || (file_data[char_index] == '*'))
253
               || (pgnfile_data[char_index] == '*'))
276
      {
254
      {
277
         // if there's a move pending, validate it
255
         // if there's a move pending, validate it
278
         if ((new_move.source[0] != -1) && (new_move.source[1] != -1) && (new_move.target[0] != -1) && (new_move.target[1] != -1))
256
         if ((new_move.source[0] != -1) && (new_move.source[1] != -1) && (new_move.target[0] != -1) && (new_move.target[1] != -1))
279
         {
257
         {
280
            Board_AppendMove (board, new_move.source[0], new_move.source[1], new_move.target[0], new_move.target[1], new_move.promotion_type, pgn_comment); // save move
258
            Board_AppendMove (board, new_move.source[0], new_move.source[1], new_move.target[0], new_move.target[1], new_move.promotion_type, pgn_comment); // save move
Line 307... Line 285...
307
            new_move.promotion_type = 0;
285
            new_move.promotion_type = 0;
308
            pgn_comment[0] = 0; // reset comment
286
            pgn_comment[0] = 0; // reset comment
309
         }
287
         }
310
 
288
 
311
         // convert the move string data to wide char
289
         // convert the move string data to wide char
312
         ConvertToWideChar (new_move.pgntext, WCHAR_SIZEOF (new_move.pgntext), &file_data[char_index]);
290
         ConvertToWideChar (new_move.pgntext, WCHAR_SIZEOF (new_move.pgntext), &pgnfile_data[char_index]);
313
 
291
 
314
         // evaluate the string in Standard Algebraic Notation and find the source, destination, part type and promotion
292
         // evaluate the string in Standard Algebraic Notation and find the source, destination, part type and promotion
315
         if (!Move_SetupFromSAN (&board->moves[board->move_count - 1], &new_move, Board_ColorToMove (board)))
293
         if (!Move_SetupFromSAN (&board->moves[board->move_count - 1], &new_move, Board_ColorToMove (board)))
316
         {
294
         {
317
            PGNFile_GameList_Shutdown (); // free the games list
295
            PGNFile_GameList_Shutdown (); // free the games list
318
            SAFE_free ((void **) &file_data); // free the file data space
296
            SAFE_free ((void **) &pgnfile_data); // free the file data space
319
            return (false); // on error, cancel
297
            return (false); // on error, cancel
320
         }
298
         }
321
 
299
 
322
         // find where it stops
300
         // find where it stops
323
         while ((char_index < file_size) && !isspace (file_data[char_index]))
301
         while ((char_index < (int) pgnfile_size) && !isspace (pgnfile_data[char_index]))
324
            char_index++; // reach the next space
302
            char_index++; // reach the next space
325
 
303
 
326
         char_index++; // remember where to continue reading (that is, after the next space)
304
         char_index++; // remember where to continue reading (that is, after the next space)
327
         continue; // and proceed to the next data
305
         continue; // and proceed to the next data
328
      }
306
      }
Line 334... Line 312...
334
 
312
 
335
   // we loaded the game we want, we no longer need the games array
313
   // we loaded the game we want, we no longer need the games array
336
   PGNFile_GameList_Shutdown ();
314
   PGNFile_GameList_Shutdown ();
337
 
315
 
338
   // we no longer need the file data space, so free it
316
   // we no longer need the file data space, so free it
339
   SAFE_free ((void **) &file_data);
317
   SAFE_free ((void **) &pgnfile_data);
340
 
318
 
341
   return (true); // game loaded successfully, return TRUE
319
   return (true); // game loaded successfully, return TRUE
342
}
320
}
343
 
321
 
344
 
322