Skip to content

How to Replace Games and Manage Deleted Flags

This guide demonstrates how to update game records in-place within a libscid database, replacing game content and toggling deleted (tombstone) status flags without requiring full database rebuilds.


1. Overview of Symbols

  • scid_database_game_replace: Replaces an existing game at a specified index with updated moves, headers, and custom flags.
  • scid_database_game_deleted_set: Sets or unsets the tombstone deleted status flag for a specific game record.
  • scid_database_game_deleted_get: Queries whether a game is currently flagged as deleted.
  • scid_database_game_get: Materialises a stored game record along with its user flags string.

2. Complete Recipe

#include <scid/scid.h>

#include <stdio.h>
#include <string.h>

static int
check(
    scid_error  error,
    const char* call)
{
    if (error == SCID_OK)
    {
        return 1;
    }

    fprintf(stderr, "%s failed with scid_error %hu\n", call, error);
    return 0;
}


static int
text_equals(
    const char* text,
    size_t      text_size,
    const char* expected)
{
    return text_size == strlen(expected) && strncmp(text, expected, text_size) == 0;
}


static int
parse_pgn(
    const char* pgn,
    scid_game** out_game)
{
    const char*    start_fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
    scid_position* position = NULL;
    char           diagnostic[1024];
    size_t         diagnostic_size = 0;

    if (!check(
            scid_position_create_from_fen(start_fen, &position), "scid_position_create_from_fen") ||
        !check(
            scid_game_create(
                position, pgn, strlen(pgn), out_game, diagnostic, sizeof(diagnostic),
                &diagnostic_size),
            "scid_game_create"))
    {
        fprintf(stderr, "%.*s\n", (int)diagnostic_size, diagnostic);
        scid_position_free(position);
        return 0;
    }

    scid_position_free(position);
    return 1;
}


int
main(void)
{
    const char*    original_pgn = "[Event \"Original\"]\n"
                                  "[Date \"2024.06.14\"]\n"
                                  "[White \"Alpha\"]\n"
                                  "[Black \"Beta\"]\n"
                                  "[Result \"1-0\"]\n"
                                  "\n"
                                  "1. e4 e5 2. Nf3 1-0\n";
    const char*    replacement_pgn = "[Event \"Replacement\"]\n"
                                     "[Date \"2025.01.02\"]\n"
                                     "[White \"Gamma\"]\n"
                                     "[Black \"Delta\"]\n"
                                     "[Result \"0-1\"]\n"
                                     "\n"
                                     "1. d4 d5 0-1\n";
    scid_database* database = NULL;
    scid_game*     original = NULL;
    scid_game*     replacement = NULL;
    scid_game*     loaded = NULL;
    char           flags[22];
    char           event[128];
    char           result[16];
    size_t         count = 0;
    size_t         event_size = 0;
    size_t         flags_size = 0;
    size_t         result_size = 0;
    int            deleted = 0;

    if (!check(scid_database_create_memory("editing", &database), "scid_database_create_memory") ||
        !parse_pgn(original_pgn, &original) || !parse_pgn(replacement_pgn, &replacement) ||
        !check(scid_database_game_add(database, original, NULL), "scid_database_game_add") ||
        !check(scid_database_game_count_get(database, &count), "scid_database_game_count_get") ||
        count != 1)
    {
        scid_game_free(loaded);
        scid_game_free(replacement);
        scid_game_free(original);
        scid_database_free(database);
        return 1;
    }


    if (!check(
            scid_database_game_replace(database, 0, replacement, "Q"),
            "scid_database_game_replace") ||
        !check(scid_database_game_count_get(database, &count), "scid_database_game_count_get") ||
        count != 1 ||
        !check(
            scid_database_game_tag_get(database, 0, "Event", event, sizeof(event), &event_size),
            "scid_database_game_tag_get") ||
        !text_equals(event, event_size, "Replacement") ||
        !check(
            scid_database_game_result_get(database, 0, result, sizeof(result), &result_size),
            "scid_database_game_result_get") ||
        !text_equals(result, result_size, "0-1") ||
        !check(
            scid_database_game_get(database, 0, &loaded, flags, sizeof(flags), &flags_size),
            "scid_database_game_get") ||
        !text_equals(flags, flags_size, "Q"))
    {
        scid_game_free(loaded);
        scid_game_free(replacement);
        scid_game_free(original);
        scid_database_free(database);
        return 1;
    }

    printf(
        "after replace: %.*s %.*s flags=%.*s\n", (int)event_size, event, (int)result_size, result,
        (int)flags_size, flags);

    scid_game_free(loaded);
    loaded = NULL;

    if (!check(scid_database_game_delete(database, 0), "scid_database_game_delete") ||
        !check(
            scid_database_game_deleted_get(database, 0, &deleted),
            "scid_database_game_deleted_get") ||
        deleted != 1 ||
        !check(scid_database_game_undelete(database, 0), "scid_database_game_undelete") ||
        !check(
            scid_database_game_deleted_get(database, 0, &deleted),
            "scid_database_game_deleted_get") ||
        deleted != 0)
    {
        scid_game_free(replacement);
        scid_game_free(original);
        scid_database_free(database);
        return 1;
    }

    printf("after undelete: deleted=%d\n", deleted);

    scid_game_free(replacement);
    scid_game_free(original);
    scid_database_free(database);
    return 0;
}

3. Key Concepts and Patterns

In-Place Replacement and Flag Management

Games can be overwritten with new content or flagged as deleted:

/* Replace existing record */
scid_database_game_replace(database, game_index, updated_game, "Q");

/* Mark game as deleted */
scid_database_game_deleted_set(database, game_index, 1);

/* Check deleted status */
int is_deleted = 0;
scid_database_game_deleted_get(database, game_index, &is_deleted);

/* Restore game by clearing deleted flag */
scid_database_game_deleted_set(database, game_index, 0);