X-Git-Url: http://winboard.nl/cgi-bin?p=xboard.git;a=blobdiff_plain;f=gamelist.c;h=34e899a8a205fe45e5803607a9abccc8b3aeb26d;hp=7775a9992164d7c215e22214964301fabc50f07b;hb=HEAD;hpb=13e03bda5c89c4457bc599bae34110b6bc76aba5 diff --git a/gamelist.c b/gamelist.c index 7775a99..34e899a 100644 --- a/gamelist.c +++ b/gamelist.c @@ -1,7 +1,8 @@ /* * gamelist.c -- Functions to manage a gamelist * - * Copyright 1995,2009 Free Software Foundation, Inc. + * Copyright 1995, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Free + * Software Foundation, Inc. * * Enhancements Copyright 2005 Alessandro Scotti * @@ -18,7 +19,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. + * along with this program. If not, see http://www.gnu.org/licenses/. * *------------------------------------------------------------------------ ** See the file ChangeLog for a revision history. */ @@ -42,12 +43,24 @@ #include "frontend.h" #include "backend.h" #include "parser.h" +#include "moves.h" +#include "gettext.h" + +#ifdef ENABLE_NLS +# define _(s) gettext (s) +# define N_(s) gettext_noop (s) +#else +# define _(s) (s) +# define N_(s) s +#endif /* Variables */ List gameList; - +extern Board initialPosition; +extern int quickFlag; +extern int movePtr; /* Local function prototypes */ @@ -56,10 +69,68 @@ static ListGame *GameListCreate P((void)); static void GameListFree P((List *)); static int GameListNewGame P((ListGame **)); +/* [AS] Wildcard pattern matching */ +Boolean +HasPattern (const char * text, const char * pattern) +{ + while( *pattern != '\0' ) { + if( *pattern == '*' ) { + while( *pattern == '*' ) { + pattern++; + } + + if( *pattern == '\0' ) { + return TRUE; + } + + while( *text != '\0' ) { + if( HasPattern( text, pattern ) ) { + return TRUE; + } + text++; + } + } + else if( (*pattern == *text) || ((*pattern == '?') && (*text != '\0')) ) { + pattern++; + text++; + continue; + } + + return FALSE; + } + + return TRUE; +} + +Boolean +SearchPattern (const char * text, const char * pattern) +{ + Boolean result = TRUE; + + if( pattern != NULL && *pattern != '\0' ) { + if( *pattern == '*' ) { + result = HasPattern( text, pattern ); + } + else { + result = FALSE; + + while( *text != '\0' ) { + if( HasPattern( text, pattern ) ) { + result = TRUE; + break; + } + text++; + } + } + } + + return result; +} + /* Delete a ListGame; implies removint it from a list. */ -static void GameListDeleteGame(listGame) - ListGame *listGame; +static void +GameListDeleteGame (ListGame *listGame) { if (listGame) { if (listGame->gameInfo.event) free(listGame->gameInfo.event); @@ -80,10 +151,10 @@ static void GameListDeleteGame(listGame) /* Free the previous list of games. */ -static void GameListFree(gameList) - List *gameList; +static void +GameListFree (List *gameList) { - while (!ListEmpty(gameList)) + while (!ListEmpty(gameList)) { GameListDeleteGame((ListGame *) gameList->head); } @@ -93,8 +164,8 @@ static void GameListFree(gameList) /* Initialize a new GameInfo structure. */ -void GameListInitGameInfo(gameInfo) - GameInfo *gameInfo; +void +GameListInitGameInfo (GameInfo *gameInfo) { gameInfo->event = NULL; gameInfo->site = NULL; @@ -110,6 +181,7 @@ void GameListInitGameInfo(gameInfo) gameInfo->whiteRating = -1; /* unknown */ gameInfo->blackRating = -1; /* unknown */ gameInfo->variant = VariantNormal; + gameInfo->variantName = NULL; gameInfo->outOfBook = NULL; gameInfo->resultDetails = NULL; } @@ -119,8 +191,8 @@ void GameListInitGameInfo(gameInfo) * * Note, that the ListGame is *not* added to any list */ -static ListGame *GameListCreate() - +static ListGame * +GameListCreate () { ListGame *listGame; @@ -133,8 +205,8 @@ static ListGame *GameListCreate() /* Creates a new game for the gamelist. */ -static int GameListNewGame(listGamePtr) - ListGame **listGamePtr; +static int +GameListNewGame (ListGame **listGamePtr) { if (!(*listGamePtr = (ListGame *) GameListCreate())) { GameListFree(&gameList); @@ -148,26 +220,30 @@ static int GameListNewGame(listGamePtr) /* Build the list of games in the open file f. * Returns 0 for success or error number. */ -int GameListBuild(f) - FILE *f; +int +GameListBuild (FILE *f) { ChessMove cm, lastStart; int gameNumber; ListGame *currentListGame = NULL; - int error; + int error, scratch=100, plyNr=0, fromX, fromY, toX, toY; int offset; - char lastComment[MSG_SIZ]; + char lastComment[MSG_SIZ], buf[MSG_SIZ]; + TimeMark t, t2; + GetTimeMark(&t); GameListFree(&gameList); yynewfile(f); gameNumber = 0; + movePtr = 0; lastStart = (ChessMove) 0; yyskipmoves = FALSE; do { - yyboardindex = 0; + yyboardindex = scratch; offset = yyoffset(); - cm = (ChessMove) yylex(); + quickFlag = plyNr + 1; + cm = (ChessMove) Myylex(); switch (cm) { case GNUChessGame: if ((error = GameListNewGame(¤tListGame))) { @@ -177,6 +253,7 @@ int GameListBuild(f) } currentListGame->number = ++gameNumber; currentListGame->offset = offset; + if(1) { CopyBoard(boards[scratch], initialPosition); plyNr = 0; currentListGame->moves = PackGame(boards[scratch]); } if (currentListGame->gameInfo.event != NULL) { free(currentListGame->gameInfo.event); } @@ -203,6 +280,7 @@ int GameListBuild(f) } currentListGame->number = ++gameNumber; currentListGame->offset = offset; + if(1) { CopyBoard(boards[scratch], initialPosition); plyNr = 0; currentListGame->moves = PackGame(boards[scratch]); } lastStart = cm; break; default: @@ -222,15 +300,24 @@ int GameListBuild(f) do { yyboardindex = 1; offset = yyoffset(); - cm = (ChessMove) yylex(); + cm = (ChessMove) Myylex(); if (cm == PGNTag) { ParsePGNTag(yy_text, ¤tListGame->gameInfo); } } while (cm == PGNTag || cm == Comment); - break; + if(1) { + int btm=0; + if(currentListGame->gameInfo.fen) ParseFEN(boards[scratch], &btm, currentListGame->gameInfo.fen, FALSE); + else CopyBoard(boards[scratch], initialPosition); + plyNr = (btm != 0); + currentListGame->moves = PackGame(boards[scratch]); + } + if(cm != NormalMove) break; + case IllegalMove: + if(appData.testLegality) break; case NormalMove: /* Allow the first game to start with an unnumbered move */ - yyskipmoves = TRUE; + yyskipmoves = FALSE; if (lastStart == (ChessMove) 0) { if ((error = GameListNewGame(¤tListGame))) { rewind(f); @@ -239,28 +326,64 @@ int GameListBuild(f) } currentListGame->number = ++gameNumber; currentListGame->offset = offset; + if(1) { CopyBoard(boards[scratch], initialPosition); plyNr = 0; currentListGame->moves = PackGame(boards[scratch]); } lastStart = MoveNumberOne; } + case WhiteCapturesEnPassant: + case BlackCapturesEnPassant: + case WhitePromotion: + case BlackPromotion: + case WhiteNonPromotion: + case BlackNonPromotion: + case WhiteKingSideCastle: + case WhiteQueenSideCastle: + case BlackKingSideCastle: + case BlackQueenSideCastle: + case WhiteKingSideCastleWild: + case WhiteQueenSideCastleWild: + case BlackKingSideCastleWild: + case BlackQueenSideCastleWild: + case WhiteHSideCastleFR: + case WhiteASideCastleFR: + case BlackHSideCastleFR: + case BlackASideCastleFR: + fromX = currentMoveString[0] - AAA; + fromY = currentMoveString[1] - ONE; + toX = currentMoveString[2] - AAA; + toY = currentMoveString[3] - ONE; + plyNr++; + ApplyMove(fromX, fromY, toX, toY, currentMoveString[4], boards[scratch]); + if(currentListGame && currentListGame->moves) PackMove(fromX, fromY, toX, toY, boards[scratch][toY][toX]); break; case WhiteWins: // [HGM] rescom: save last comment as result details case BlackWins: case GameIsDrawn: case GameUnfinished: + if(!currentListGame) break; + if(currentListGame->gameInfo.result == GameUnfinished) + currentListGame->gameInfo.result = cm; // correct result tag with actual result if (currentListGame->gameInfo.resultDetails != NULL) { free(currentListGame->gameInfo.resultDetails); } - if(yy_text[0] == '{') { char *p; - strcpy(lastComment, yy_text+1); - if(p = strchr(lastComment, '}')) *p = 0; + if(yy_text[0] == '{') { + char *p; + safeStrCpy(lastComment, yy_text+1, sizeof(lastComment)/sizeof(lastComment[0])); + if((p = strchr(lastComment, '}'))) *p = 0; currentListGame->gameInfo.resultDetails = StrSave(lastComment); } break; default: break; } + if(gameNumber % 1000 == 0) { + snprintf(buf, MSG_SIZ, _("Reading game file (%d)"), gameNumber); + DisplayTitle(buf); DoEvents(); + } } while (cm != (ChessMove) 0); + if(currentListGame) { + if(!currentListGame->moves) DisplayError("Game cache overflowed\nPosition-searching might not work properly", 0); if (appData.debugMode) { for (currentListGame = (ListGame *) gameList.head; @@ -272,7 +395,11 @@ int GameListBuild(f) PrintPGNTags(debugFP, ¤tListGame->gameInfo); } } - + } + if(appData.debugMode) { GetTimeMark(&t2);printf("GameListBuild %ld msec\n", SubtractTimeMarks(&t2,&t)); } + quickFlag = 0; + PackGame(boards[scratch]); // for appending end-of-game marker. + DisplayTitle("WinBoard"); rewind(f); yyskipmoves = FALSE; return 0; @@ -281,8 +408,8 @@ int GameListBuild(f) /* Clear an existing GameInfo structure. */ -void ClearGameInfo(gameInfo) - GameInfo *gameInfo; +void +ClearGameInfo (GameInfo *gameInfo) { if (gameInfo->event != NULL) { free(gameInfo->event); @@ -314,28 +441,25 @@ void ClearGameInfo(gameInfo) if (gameInfo->extraTags != NULL) { free(gameInfo->extraTags); } + if (gameInfo->variantName != NULL) { + free(gameInfo->variantName); + } if (gameInfo->outOfBook != NULL) { free(gameInfo->outOfBook); } - if (gameInfo->resultDetails != NULL) { - free(gameInfo->resultDetails); - } - GameListInitGameInfo(gameInfo); } /* [AS] Replaced by "dynamic" tag selection below */ char * -GameListLineOld(number, gameInfo) - int number; - GameInfo *gameInfo; +GameListLineOld (int number, GameInfo *gameInfo) { char *event = (gameInfo->event && strcmp(gameInfo->event, "?") != 0) ? gameInfo->event : gameInfo->site ? gameInfo->site : "?"; char *white = gameInfo->white ? gameInfo->white : "?"; char *black = gameInfo->black ? gameInfo->black : "?"; char *date = gameInfo->date ? gameInfo->date : "?"; - int len = 10 + strlen(event) + 2 + strlen(white) + 1 + + int len = 10 + strlen(event) + 2 + strlen(white) + 1 + strlen(black) + 11 + strlen(date) + 1; char *ret = (char *) malloc(len); sprintf(ret, "%d. %s, %s-%s, %s, %s", @@ -345,12 +469,13 @@ GameListLineOld(number, gameInfo) #define MAX_FIELD_LEN 80 /* To avoid overflowing the buffer */ -char * GameListLine( int number, GameInfo * gameInfo ) +char * +GameListLine (int number, GameInfo * gameInfo) { - char buffer[1024]; + char buffer[2*MSG_SIZ]; char * buf = buffer; char * glt = appData.gameListTags; - + buf += sprintf( buffer, "%d.", number ); while( *glt != '\0' ) { @@ -377,24 +502,26 @@ char * GameListLine( int number, GameInfo * gameInfo ) strncpy( buf, gameInfo->black ? gameInfo->black : "?", MAX_FIELD_LEN ); break; case GLT_RESULT: - strcpy( buf, PGNResult(gameInfo->result) ); + safeStrCpy( buf, PGNResult(gameInfo->result), 2*MSG_SIZ ); break; case GLT_WHITE_ELO: if( gameInfo->whiteRating > 0 ) - sprintf( buf, "%d", gameInfo->whiteRating ); + sprintf( buf, "%d", gameInfo->whiteRating ); else - strcpy( buf, "?" ); + safeStrCpy( buf, "?" , 2*MSG_SIZ); break; case GLT_BLACK_ELO: if( gameInfo->blackRating > 0 ) sprintf( buf, "%d", gameInfo->blackRating ); else - strcpy( buf, "?" ); + safeStrCpy( buf, "?" , 2*MSG_SIZ); break; case GLT_TIME_CONTROL: strncpy( buf, gameInfo->timeControl ? gameInfo->timeControl : "?", MAX_FIELD_LEN ); break; case GLT_VARIANT: + strncpy( buf, gameInfo->variantName ? gameInfo->variantName : VariantName(gameInfo->variant), MAX_FIELD_LEN ); +// strncpy( buf, VariantName(gameInfo->variant), MAX_FIELD_LEN ); break; case GLT_OUT_OF_BOOK: strncpy( buf, gameInfo->outOfBook ? gameInfo->outOfBook : "?", MAX_FIELD_LEN ); @@ -422,7 +549,8 @@ char * GameListLine( int number, GameInfo * gameInfo ) return strdup( buffer ); } -char * GameListLineFull( int number, GameInfo * gameInfo ) +char * +GameListLineFull (int number, GameInfo * gameInfo) { char * event = gameInfo->event ? gameInfo->event : "?"; char * site = gameInfo->site ? gameInfo->site : "?"; @@ -432,7 +560,7 @@ char * GameListLineFull( int number, GameInfo * gameInfo ) char * date = gameInfo->date ? gameInfo->date : "?"; char * oob = gameInfo->outOfBook ? gameInfo->outOfBook : ""; char * reason = gameInfo->resultDetails ? gameInfo->resultDetails : ""; - + int len = 64 + strlen(event) + strlen(site) + strlen(white) + strlen(black) + strlen(date) + strlen(oob) + strlen(reason); char *ret = (char *) malloc(len); @@ -442,3 +570,114 @@ char * GameListLineFull( int number, GameInfo * gameInfo ) return ret; } +// --------------------------------------- Game-List options dialog -------------------------------------- + +// back-end +typedef struct { + char id; + char * name; +} GLT_Item; + +// back-end: translation table tag id-char <-> full tag name +static GLT_Item GLT_ItemInfo[] = { + { GLT_EVENT, "Event" }, + { GLT_SITE, "Site" }, + { GLT_DATE, "Date" }, + { GLT_ROUND, "Round" }, + { GLT_PLAYERS, "Players" }, + { GLT_RESULT, "Result" }, + { GLT_WHITE_ELO, "White Rating" }, + { GLT_BLACK_ELO, "Black Rating" }, + { GLT_TIME_CONTROL,"Time Control" }, + { GLT_VARIANT, "Variant" }, + { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK }, + { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom + { 0, 0 } +}; + +char lpUserGLT[LPUSERGLT_SIZE]; + +// back-end: convert the tag id-char to a full tag name +char * +GLT_FindItem (char id) +{ + char * result = 0; + + GLT_Item * list = GLT_ItemInfo; + + while( list->id != 0 ) { + if( list->id == id ) { + result = list->name; + break; + } + + list++; + } + + return result; +} + +// back-end: build the list of tag names +void +GLT_TagsToList (char *tags) +{ + char * pc = tags; + + GLT_ClearList(); + + while( *pc ) { + GLT_AddToList( GLT_FindItem(*pc) ); + pc++; + } + + GLT_AddToList( " --- Hidden tags --- " ); + + pc = GLT_ALL_TAGS; + + while( *pc ) { + if( strchr( tags, *pc ) == 0 ) { + GLT_AddToList( GLT_FindItem(*pc) ); + } + pc++; + } + + GLT_DeSelectList(); +} + +// back-end: retrieve item from dialog and translate to id-char +char +GLT_ListItemToTag (int index) +{ + char result = '\0'; + char name[MSG_SIZ]; + + GLT_Item * list = GLT_ItemInfo; + + if( GLT_GetFromList(index, name) ) { + while( list->id != 0 ) { + if( strcmp( list->name, name ) == 0 ) { + result = list->id; + break; + } + + list++; + } + } + + return result; +} + +// back-end: add items id-chars one-by-one to temp tags string +void +GLT_ParseList () +{ + char * pc = lpUserGLT; + int idx = 0; + char id; + + do { + id = GLT_ListItemToTag( idx ); + *pc++ = id; + idx++; + } while( id != '\0' ); +}