# HG changeset patch # User Mike Becker # Date 1776427690 -7200 # Node ID 36dd94278142380e680ecb28aecfa5db73d8b4ca # Parent bdc9528d3e2be473046d0f90c4d1522b6e8d0de1 fix that PGN (with comments) can exceed 80 chars resolves #824 diff -r bdc9528d3e2b -r 36dd94278142 src/chess/pgn.c --- a/src/chess/pgn.c Fri Apr 17 13:17:34 2026 +0200 +++ b/src/chess/pgn.c Fri Apr 17 14:08:10 2026 +0200 @@ -28,6 +28,8 @@ */ #include "pgn.h" + +#include #include #include @@ -177,6 +179,23 @@ return 0; } +static void pgn_insert_newlines(char *block) { + size_t pos = 0; + size_t last_space_pos = 0; + size_t line_len = 0; + while (block[pos] != '\0') { + if (block[pos] == ' ') { + last_space_pos = pos; + } + line_len++; + if (line_len > 80) { + block[last_space_pos] = '\n'; + line_len = pos - last_space_pos; + } + pos++; + } +} + void write_pgn(FILE* stream, GameState *gamestate, GameInfo *gameinfo) { // TODO: tag pairs @@ -197,40 +216,76 @@ fprintf(stream, "[Result \"%s\"]\n\n", result); /* moves */ + size_t moveblkcap = 4096; + char *moveblk = malloc(moveblkcap); + char *moveblkptr = moveblk; + if (moveblk == NULL) { + // TODO: error handling (for the entire function actually) + abort(); + } for (unsigned i = 0 ; i < gamestate->movecount ; i++) { - + /* reallocate move block buffer if needed */ + { + size_t moveblksize = moveblkptr - moveblk; + if (moveblksize + 128 < moveblkcap) { + moveblkcap *= 2; + char *newmoveblk = realloc(moveblk, moveblkcap); + if (newmoveblk == NULL) { + free(moveblk); + abort(); + } + moveblk = newmoveblk; + moveblkptr = moveblk + moveblksize; + } + } + + int snpr; /* return value of printf calls */ + if (i % 2 == 0) { - fprintf(stream, "%d. %s", 1+i/2, gamestate->moves[i].string); + snpr = snprintf(moveblkptr, 16, "%d. %s", + 1+i/2, gamestate->moves[i].string); } else { - fprintf(stream, "%s", gamestate->moves[i].string); + snpr = snprintf(moveblkptr, 16, "%s", + gamestate->moves[i].string); } + moveblkptr += snpr; /* add clock times when the game was under time control */ if (gameinfo->timecontrol) { - char clkstr[16]; + memcpy(moveblkptr, " {[%clk ", 8); + moveblkptr += 8; unsigned clkmv = i + 2; /* time for the next move! */ uint16_t clk = remaining_movetime2(gameinfo, gamestate, clkmv); - print_clk(clk, clkstr, true); - fprintf(stream, " {[%%clk %s]}", clkstr); + snpr = print_clk(clk, moveblkptr, true); + moveblkptr += snpr; + *(moveblkptr++) = ']'; + *(moveblkptr++) = '}'; /* elapsed move time */ - print_clk(gamestate->moves[i].movetime.tv_sec, clkstr, true); - fprintf(stream, " {[%%emt %s]}", clkstr); + memcpy(moveblkptr, " {[%emt ", 8); + moveblkptr += 8; + uint16_t emt = gamestate->moves[i].movetime.tv_sec; + snpr = print_clk(emt, moveblkptr, true); + moveblkptr += snpr; + *(moveblkptr++) = ']'; + *(moveblkptr++) = '}'; } - /* line break every 10 half-moves */ - if ((i+1) % 10) { - fputc(' ', stream); - } else { - fputc('\n', stream); - } + *(moveblkptr++) = ' '; } - if (result[0] == '*') { - fputc('\n', stream); - } else { - fprintf(stream, "%s\n", result); + if (result[0] != '*') { + size_t rlen = strlen(result); + memcpy(moveblkptr, result, rlen); + moveblkptr += rlen; } + *(moveblkptr++) = '\n'; + *moveblkptr = 0; + + pgn_insert_newlines(moveblk); + fputs(moveblk, stream); + + free(moveblk); } static size_t fen_pieces(char *str, GameState *gamestate) { diff -r bdc9528d3e2b -r 36dd94278142 src/chess/rules.c --- a/src/chess/rules.c Fri Apr 17 13:17:34 2026 +0200 +++ b/src/chess/rules.c Fri Apr 17 14:08:10 2026 +0200 @@ -823,13 +823,13 @@ return used_time >= total_time ? 0 : total_time - used_time; } -void print_clk(uint16_t time, char *str, bool always_hours) { +int print_clk(uint16_t time, char *str, bool always_hours) { unsigned hours = time / 3600; unsigned minutes = (time % 3600) / 60; unsigned seconds = time % 60; if (hours > 0 || always_hours) { - snprintf(str, 9, "%u:%02u:%02u", hours, minutes, seconds); + return snprintf(str, 9, "%u:%02u:%02u", hours, minutes, seconds); } else { - snprintf(str, 6, "%02u:%02u", minutes, seconds); + return snprintf(str, 6, "%02u:%02u", minutes, seconds); } } diff -r bdc9528d3e2b -r 36dd94278142 src/chess/rules.h --- a/src/chess/rules.h Fri Apr 17 13:17:34 2026 +0200 +++ b/src/chess/rules.h Fri Apr 17 14:08:10 2026 +0200 @@ -263,7 +263,7 @@ * @param str the target buffer (should be at least 10 chars large) * @param always_hours if hours should always be printed */ -void print_clk(uint16_t time, char *str, bool always_hours); +int print_clk(uint16_t time, char *str, bool always_hours); #endif /* RULES_H */