src/chess/pgn.c

changeset 107
36dd94278142
parent 106
bdc9528d3e2b
equal deleted inserted replaced
106:bdc9528d3e2b 107:36dd94278142
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 * 27 *
28 */ 28 */
29 29
30 #include "pgn.h" 30 #include "pgn.h"
31
32 #include <stdlib.h>
31 #include <ctype.h> 33 #include <ctype.h>
32 #include <string.h> 34 #include <string.h>
33 35
34 enum { 36 enum {
35 pgn_error_missing_quote = 1, 37 pgn_error_missing_quote = 1,
175 } 177 }
176 178
177 return 0; 179 return 0;
178 } 180 }
179 181
182 static void pgn_insert_newlines(char *block) {
183 size_t pos = 0;
184 size_t last_space_pos = 0;
185 size_t line_len = 0;
186 while (block[pos] != '\0') {
187 if (block[pos] == ' ') {
188 last_space_pos = pos;
189 }
190 line_len++;
191 if (line_len > 80) {
192 block[last_space_pos] = '\n';
193 line_len = pos - last_space_pos;
194 }
195 pos++;
196 }
197 }
198
180 void write_pgn(FILE* stream, GameState *gamestate, GameInfo *gameinfo) { 199 void write_pgn(FILE* stream, GameState *gamestate, GameInfo *gameinfo) {
181 // TODO: tag pairs 200 // TODO: tag pairs
182 201
183 /* Result */ 202 /* Result */
184 char *result; 203 char *result;
195 result = "*"; 214 result = "*";
196 } 215 }
197 fprintf(stream, "[Result \"%s\"]\n\n", result); 216 fprintf(stream, "[Result \"%s\"]\n\n", result);
198 217
199 /* moves */ 218 /* moves */
219 size_t moveblkcap = 4096;
220 char *moveblk = malloc(moveblkcap);
221 char *moveblkptr = moveblk;
222 if (moveblk == NULL) {
223 // TODO: error handling (for the entire function actually)
224 abort();
225 }
200 for (unsigned i = 0 ; i < gamestate->movecount ; i++) { 226 for (unsigned i = 0 ; i < gamestate->movecount ; i++) {
201 227 /* reallocate move block buffer if needed */
228 {
229 size_t moveblksize = moveblkptr - moveblk;
230 if (moveblksize + 128 < moveblkcap) {
231 moveblkcap *= 2;
232 char *newmoveblk = realloc(moveblk, moveblkcap);
233 if (newmoveblk == NULL) {
234 free(moveblk);
235 abort();
236 }
237 moveblk = newmoveblk;
238 moveblkptr = moveblk + moveblksize;
239 }
240 }
241
242 int snpr; /* return value of printf calls */
243
202 if (i % 2 == 0) { 244 if (i % 2 == 0) {
203 fprintf(stream, "%d. %s", 1+i/2, gamestate->moves[i].string); 245 snpr = snprintf(moveblkptr, 16, "%d. %s",
246 1+i/2, gamestate->moves[i].string);
204 } else { 247 } else {
205 fprintf(stream, "%s", gamestate->moves[i].string); 248 snpr = snprintf(moveblkptr, 16, "%s",
206 } 249 gamestate->moves[i].string);
250 }
251 moveblkptr += snpr;
207 252
208 /* add clock times when the game was under time control */ 253 /* add clock times when the game was under time control */
209 if (gameinfo->timecontrol) { 254 if (gameinfo->timecontrol) {
210 char clkstr[16]; 255 memcpy(moveblkptr, " {[%clk ", 8);
256 moveblkptr += 8;
211 unsigned clkmv = i + 2; /* time for the next move! */ 257 unsigned clkmv = i + 2; /* time for the next move! */
212 uint16_t clk = remaining_movetime2(gameinfo, gamestate, clkmv); 258 uint16_t clk = remaining_movetime2(gameinfo, gamestate, clkmv);
213 print_clk(clk, clkstr, true); 259 snpr = print_clk(clk, moveblkptr, true);
214 fprintf(stream, " {[%%clk %s]}", clkstr); 260 moveblkptr += snpr;
261 *(moveblkptr++) = ']';
262 *(moveblkptr++) = '}';
215 263
216 /* elapsed move time */ 264 /* elapsed move time */
217 print_clk(gamestate->moves[i].movetime.tv_sec, clkstr, true); 265 memcpy(moveblkptr, " {[%emt ", 8);
218 fprintf(stream, " {[%%emt %s]}", clkstr); 266 moveblkptr += 8;
219 } 267 uint16_t emt = gamestate->moves[i].movetime.tv_sec;
220 268 snpr = print_clk(emt, moveblkptr, true);
221 /* line break every 10 half-moves */ 269 moveblkptr += snpr;
222 if ((i+1) % 10) { 270 *(moveblkptr++) = ']';
223 fputc(' ', stream); 271 *(moveblkptr++) = '}';
224 } else { 272 }
225 fputc('\n', stream); 273
226 } 274 *(moveblkptr++) = ' ';
227 } 275 }
228 276
229 if (result[0] == '*') { 277 if (result[0] != '*') {
230 fputc('\n', stream); 278 size_t rlen = strlen(result);
231 } else { 279 memcpy(moveblkptr, result, rlen);
232 fprintf(stream, "%s\n", result); 280 moveblkptr += rlen;
233 } 281 }
282 *(moveblkptr++) = '\n';
283 *moveblkptr = 0;
284
285 pgn_insert_newlines(moveblk);
286 fputs(moveblk, stream);
287
288 free(moveblk);
234 } 289 }
235 290
236 static size_t fen_pieces(char *str, GameState *gamestate) { 291 static size_t fen_pieces(char *str, GameState *gamestate) {
237 size_t i = 0; 292 size_t i = 0;
238 for (int row = 7 ; row >= 0 ; row--) { 293 for (int row = 7 ; row >= 0 ; row--) {

mercurial