| 198 } |
200 } |
| 199 pos++; |
201 pos++; |
| 200 } |
202 } |
| 201 } |
203 } |
| 202 |
204 |
| |
205 static const char *pgn_date(GameState *gamestate) { |
| |
206 static char date[16]; |
| |
207 time_t dateseconds; |
| |
208 if (gamestate->movecount == 0) { |
| |
209 struct timeval curtimestamp; |
| |
210 gettimeofday(&curtimestamp, NULL); |
| |
211 dateseconds = curtimestamp.tv_sec; |
| |
212 } else { |
| |
213 dateseconds = (time_t) gamestate->moves[0].timestamp.tv_sec; |
| |
214 } |
| |
215 struct tm *tm = gmtime(&dateseconds); |
| |
216 if (tm == NULL) { |
| |
217 /* fallback - should never happen in reality */ |
| |
218 strncpy(date, "????.??.??", sizeof(date)); |
| |
219 } else { |
| |
220 int year = tm->tm_year + 1900; |
| |
221 int month = tm->tm_mon + 1; |
| |
222 int day = tm->tm_mday; |
| |
223 #ifdef __GNUC__ |
| |
224 /* this is required to tell GCC that it does not need to warn |
| |
225 * about the small buffer size of the date string. |
| |
226 */ |
| |
227 if (year < 1900 || year > 9999) __builtin_unreachable(); |
| |
228 if (month < 1 || month > 12) __builtin_unreachable(); |
| |
229 if (day < 1 || day > 31) __builtin_unreachable(); |
| |
230 #endif |
| |
231 snprintf(date, sizeof(date), "%04d.%02d.%02d", |
| |
232 year, month, day); |
| |
233 } |
| |
234 return date; |
| |
235 } |
| |
236 |
| 203 void write_pgn(FILE* stream, GameState *gamestate, GameInfo *gameinfo, |
237 void write_pgn(FILE* stream, GameState *gamestate, GameInfo *gameinfo, |
| 204 bool export_comments) { |
238 bool export_comments) { |
| 205 // TODO: tag pairs |
239 /* STR tag pairs */ |
| 206 |
240 fprintf(stream, "[Event \"%s\"]\n", "terminal-chess game"); |
| 207 /* Result */ |
241 fprintf(stream, "[Site \"%s\"]\n", "Somewhere on Earth"); |
| |
242 fprintf(stream, "[Date \"%s\"]\n", pgn_date(gamestate)); |
| |
243 fprintf(stream, "[Round \"%s\"]\n", "-"); |
| |
244 // TODO: maybe allow players to enter their names before game starts |
| |
245 fprintf(stream, "[White \"%s\"]\n", "Anonymous"); |
| |
246 fprintf(stream, "[Black \"%s\"]\n", "Anonymous"); |
| |
247 |
| 208 char *result; |
248 char *result; |
| 209 if (gamestate->stalemate || gamestate->remis) { |
249 if (gamestate->stalemate || gamestate->remis) { |
| 210 result = "1/2-1/2"; |
250 result = "1/2-1/2"; |
| 211 } else if (gamestate->checkmate || gamestate->resign) { |
251 } else if (gamestate->checkmate || gamestate->resign) { |
| 212 if (gamestate->movecount > 0) { |
252 if (gamestate->movecount > 0) { |