Files
chess-games/pgn-extract/taglines.c
2024-01-22 07:30:05 +01:00

268 lines
9.0 KiB
C

/*
* This file is part of pgn-extract: a Portable Game Notation (PGN) extractor.
* Copyright (C) 1994-2022 David J. Barnes
*
* pgn-extract is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pgn-extract is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pgn-extract. If not, see <http://www.gnu.org/licenses/>.
*
* David J. Barnes may be contacted as d.j.barnes@kent.ac.uk
* https://www.cs.kent.ac.uk/people/staff/djb/
*/
#include <stdio.h>
#include <stdlib.h>
#include "bool.h"
#include "defs.h"
#include "typedef.h"
#include "tokens.h"
#include "taglist.h"
#include "lex.h"
#include "lines.h"
#include "lists.h"
#include "moves.h"
#include "output.h"
#include "taglines.h"
static FILE *yyin = NULL;
/* Read the list of extraction criteria from TagFile.
* This doesn't use the normal lexical analyser before the
* PGN files are processed but circumvents next_token by
* calling get_tag() and get_string. This allows it to detect
* EOF before yywrap() is called.
* Be careful to leave lex in the right state.
*/
void
read_tag_file(const char *TagFile)
{
yyin = fopen(TagFile, "r");
if (yyin != NULL) {
Boolean keep_reading = TRUE;
while (keep_reading) {
char *line = next_input_line(yyin);
if (line != NULL) {
keep_reading = process_tag_line(TagFile, line);
}
else {
keep_reading = FALSE;
}
}
(void) fclose(yyin);
/* Call yywrap in order to set up for the next (first) input file. */
(void) yywrap();
yyin = NULL;
}
else {
fprintf(GlobalState.logfile,
"Unable to open %s for reading.\n", TagFile);
exit(1);
}
}
/* Read the contents of a file that lists the
* required output ordering for tags.
*/
void
read_tag_roster_file(const char *RosterFile)
{
Boolean keep_reading = TRUE;
yyin = must_open_file(RosterFile, "r");
while (keep_reading) {
char *line = next_input_line(yyin);
if (line != NULL) {
keep_reading = process_roster_line(line);
}
else {
keep_reading = FALSE;
}
}
(void) fclose(yyin);
/* Call yywrap in order to set up for the next (first) input file. */
(void) yywrap();
}
/* Extract a tag/value pair from the given line.
* Return TRUE if this was successful.
*/
Boolean
process_tag_line(const char *TagFile, char *line)
{
Boolean keep_reading = TRUE;
if (non_blank_line(line)) {
unsigned char *linep = (unsigned char *) line;
/* We should find a tag. */
LinePair resulting_line = gather_tag(line, linep);
TokenType tag_token;
/* Pick up where we are now. */
line = resulting_line.line;
linep = resulting_line.linep;
tag_token = resulting_line.token;
if (tag_token != NO_TOKEN) {
/* Pick up which tag it was. */
int tag_index = yylval.tag_index;
/* Allow for an optional operator. */
TagOperator operator = NONE;
/* Skip whitespace. */
while (is_character_class(*linep, WHITESPACE)) {
linep++;
}
/* Allow for an optional operator. */
if (is_character_class(*linep, OPERATOR)) {
switch (*linep) {
case '<':
linep++;
if (*linep == '=') {
linep++;
operator = LESS_THAN_OR_EQUAL_TO;
}
else if (*linep == '>') {
linep++;
operator = NOT_EQUAL_TO;
}
else {
operator = LESS_THAN;
}
break;
case '>':
linep++;
if (*linep == '=') {
linep++;
operator = GREATER_THAN_OR_EQUAL_TO;
}
else {
operator = GREATER_THAN;
}
break;
case '=':
linep++;
if (*linep == '~') {
operator = REGEX;
linep++;
}
else {
operator = EQUAL_TO;
}
break;
default:
fprintf(GlobalState.logfile,
"Internal error: unknown operator in %s\n", line);
linep++;
break;
}
/* Skip whitespace. */
while (is_character_class(*linep, WHITESPACE)) {
linep++;
}
}
if (is_character_class(*linep, DOUBLE_QUOTE)) {
/* A string, as expected. */
linep++;
resulting_line = gather_string(line, linep);
line = resulting_line.line;
linep = resulting_line.linep;
if (tag_token == TAG) {
/* Treat FEN and FENPattern tags as special cases.
* Use the position they represent to indicate
* a positional match.
*/
if (tag_index == FEN_TAG) {
add_fen_positional_match(yylval.token_string);
(void) free((void *) yylval.token_string);
}
else if (tag_index == PSEUDO_FEN_PATTERN_TAG ||
tag_index == PSEUDO_FEN_PATTERN_I_TAG) {
/* Skip whitespace. */
while (is_character_class(*linep, WHITESPACE)) {
linep++;
}
const char *label;
if(*linep != '\0') {
/* Treat the remainder of the line as a label. */
label = (const char *) linep;
}
else {
label = NULL;
}
/* Generate an inverted version as well if
* it is PSEUDO_FEN_PATTERN_I_TAG.
*/
add_fen_pattern_match(yylval.token_string,
tag_index == PSEUDO_FEN_PATTERN_I_TAG, label);
(void) free((void *) yylval.token_string);
}
else {
add_tag_to_list(tag_index, yylval.token_string, operator);
(void) free((void *) yylval.token_string);
}
}
else {
if (!GlobalState.skipping_current_game) {
fprintf(GlobalState.logfile,
"File %s: unrecognised tag name %s\n",
TagFile, line);
}
(void) free((void *) yylval.token_string);
}
}
else {
if (!GlobalState.skipping_current_game) {
fprintf(GlobalState.logfile,
"File %s: missing quoted tag string in %s at %s\n",
TagFile, line, linep);
}
}
}
else {
/* Terminate the reading, as we have run out of tags. */
keep_reading = FALSE;
}
}
return keep_reading;
}
/* Extract a tag name from the given line.
* Return TRUE if this was successful.
*/
Boolean
process_roster_line(char *line)
{
Boolean keep_reading = TRUE;
if (non_blank_line(line)) {
unsigned char *linep = (unsigned char *) line;
/* We should find a tag. */
LinePair resulting_line = gather_tag(line, linep);
TokenType tag_token;
/* Pick up where we are now. */
line = resulting_line.line;
linep = resulting_line.linep;
tag_token = resulting_line.token;
if (tag_token != NO_TOKEN) {
/* Pick up which tag it was. */
int tag_index = yylval.tag_index;
add_to_output_tag_order((TagName) tag_index);
}
else {
/* Terminate the reading, as we have run out of tags. */
keep_reading = FALSE;
}
}
return keep_reading;
}