libpgn

PGN FILE PARSER

Overview

  1. Download
  2. Installation
  3. Test
  4. PGN File Structure
  5. Usage (In a Nutshell)
  6. Accessing the Parsed Information
  7. Library Structure
  8. Foreign Function Interface (FFI)
  9. Examples

Download

Clone libpgn (latest) from the git repository:

Installation

Compile libpgn as shared & static library:

Test

Make sure libpgn works correctly (optional):

PGN File Structure

[Event "RUDAR XXVIII - IM ROUND ROBIN"]
[Site "Pozarevac, Serbia"]
[Round "9.2"]
[Date "2024.8.14"]
[White "Ostojic, Nikola"]
[Black "Ilincic, Zlatko"]
[WhiteElo "2248"]
[BlackElo "2274"]
[Result "1/2-1/2"]
1.Nf3 d5 2.b3 c5 3.e3 Nc6 4.Bb2 Nf6 5.Bb5 Bd7 6.O-O e6 7.Bxc6 Bxc6 8.Ne5 1/2-1/2

.pgn file consists of 2 parts:

Metadata (Tag Pair)

Moves (Movetext)

Usage (In a Nutshell)

#include <pgn.h>
#include <stdio.h>

int main(void)
{
    pgn_t *pgn = pgn_init();
    pgn_parse(pgn,
              "[Event \"Global Championship Finals 2022\"]\n"
              "[Result \"*\"]\n"
              "\n"
              "1. e4 e5 2. Ke2? *");

    pgn_cleanup(pgn);
    return 0;
}

Let's iterate through every pgn_* functions:

Accessing the Parsed Information

You can pull the parsed information through modules such as metadata.h, score.h, moves.h, and more:

#include <pgn.h>
#include <stdio.h>

int main(void)
{
    pgn_t *pgn = pgn_init();
    pgn_parse(pgn,
              "[Event \"Global Championship Finals 2022\"]\n"
              "[Result \"*\"]\n"
              "\n"
              "1. e4 e5 2. Ke2? *");


    printf("%s\n", pgn_metadata_get(pgn->metadata, "Event"));
    printf("Featuring 'Bongcloud Attack'\n\n");

    for (int i = 0; i < pgn->moves->length; i++) {
        pgn_move_t white = pgn->moves->values[i].white;
        pgn_move_t black = pgn->moves->values[i].black;
        printf("%d.\n  %s\n  %s\n", i + 1, white.notation, black.notation);
    }

    printf("%s\n", pgn_score_to_string(pgn->score));


    pgn_cleanup(pgn);
    return 0;
}

Output:

Global Championship Finals 2022
Featuring 'Bongcloud Attack'

1.
  e4
  e5
2.
  Ke2?

*

Libray Structure

Everything is self-documented. For starters, look into the pgn.h module:

typedef struct pgn_t {
    pgn_metadata_t *metadata;
    pgn_moves_t *moves;
    pgn_score_t score;
} pgn_t;

The data structure of libpgn resembles the PGN file structure (see 4.) itself. If you're familiar with C, you can dig down (read the code) by yourself, since everything is self-documented.


Metadata (metadata.h):

typedef struct pgn_metadata_t {
    __pgn_metadata_item_t *items;
    size_t length, size;
} pgn_metadata_t;
typedef struct __pgn_metadata_item_t {
    pgn_buffer_t *key;
    pgn_buffer_t *value;
} __pgn_metadata_item_t;

Basically a hash map.

PGN_EXPORT void pgn_metadata_insert(pgn_metadata_t *metadata, char *key, char *value);
PGN_EXPORT char *pgn_metadata_get(pgn_metadata_t *metadata, char *key);
PGN_EXPORT void pgn_metadata_delete(pgn_metadata_t *metadata, char *key);

You can play with it using these functions. Generally, look for the one that has a PGN_EXPORT macro.


Moves (moves.h):

struct pgn_moves_t {
    __pgn_moves_item_t *values;
    size_t length;
    size_t size;
};
struct __pgn_moves_item_t {
    pgn_move_t white;
    pgn_move_t black;
};
typedef struct pgn_move_t {
    pgn_piece_t piece, promoted_to;
    char notation[__PGN_MOVE_NOTATION_SIZE];
    int castles;
    bool captures;
    bool en_passant;
    pgn_check_t check;
    pgn_coordinate_t from, dest;
    pgn_annotation_t annotation;
    pgn_comments_t *comments;
    pgn_alternative_moves_t *alternatives;
} pgn_move_t;

An array that holds each move, it supports: annotation (!!, ?!, ??, etc.), comments ({hi}, {from libpgn}), alternative moves (69. Be4 ( 69. Be2 69... e4 ) 69... Rxe5?!), and more.


Quick tip: anything that has this signature (T *name) where T is a type is considered an array. The type name is usually plural (s).

Foreign Function Interface (FFI)

I am planning to add bindings for other languages (python, zig, etc.), there's one example for ada.

Examples

You can find examples on the tests/, and bin/ folders.


Here are softwares that uses libpgn: