1 /* pgn.cc
2 
3    GNU Chess frontend
4 
5    Copyright (C) 2001-2020 Free Software Foundation, Inc.
6 
7    GNU Chess is based on the two research programs
8    Cobalt by Chua Kong-Sian and Gazebo by Stuart Cracraft.
9 
10    This program is free software: you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation, either version 3 of the License, or
13    (at your option) any later version.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 
23    Contact Info:
24      bug-gnu-chess@gnu.org
25      cracraft@ai.mit.edu, cracraft@stanfordalumni.org, cracraft@earthlink.net
26 */
27 
28 #include <stdio.h>
29 #include <sys/time.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <time.h>
33 #include <errno.h>
34 
35 #include "common.h"
36 #include "version.h"
37 #include "lexpgn.h"
38 #include "gettext.h"
39 
40 #define _(str) gettext (str)
41 
42 #define NULL2EMPTY(x) ( (x) ? (x) : "")
43 
44 extern FILE *yyin;
45 
46 extern int yylex (void);
47 
PGNSaveToFile(const char * file,const char * resultstr)48 void PGNSaveToFile (const char *file, const char *resultstr)
49 /****************************************************************************
50  *
51  *  To save a game into PGN format to a file, if the file does not exist.
52  *  If the file exists, it will not be written and the user will be informed.
53  *
54  ****************************************************************************/
55 {
56    FILE *fp;
57    char s[100];
58    int len;
59    char *p;
60    int i;
61    time_t secs;
62    struct tm *timestruct;
63 
64    fp = fopen(file, "r");
65    if (fp) {
66      fclose(fp);
67      printf(_("File '%s' already exists. Please delete it first, or choose a different file name.\n"), file);
68      return;
69    }
70 
71    fp = fopen (file, "w");
72    if (fp == NULL)
73    {
74       printf(_("Cannot write to file %s\n"), file);
75       return;
76    }
77 
78    /* Write the seven tags */
79    fprintf (fp, "[Event \"%s\"]\n", NULL2EMPTY(pgn_event));
80    fprintf (fp, "[Site \"%s\"]\n", NULL2EMPTY(pgn_site));
81    secs=time(0);
82    if (pgn_date)
83      fprintf(fp,"[Date \"%s\"]\n", pgn_date);
84    else {
85      timestruct=localtime((time_t*) &secs);
86      fprintf(fp,"[Date \"%4d.%02d.%02d\"]\n",timestruct->tm_year+1900,
87              timestruct->tm_mon+1,timestruct->tm_mday);
88    }
89    fprintf (fp, "[Round \"%s\"]\n", NULL2EMPTY(pgn_round));
90 
91    if (pgn_white)
92      fprintf (fp, "[White \"%s\"]\n", pgn_white);
93    else if (computer == white)
94      fprintf (fp, "[White \"%s %s\"]\n",PROGRAM,VERSION);
95    else
96      fprintf (fp, "[White \"%s\"]\n",name);
97 
98    if (pgn_black)
99      fprintf (fp, "[Black \"%s\"]\n", pgn_black);
100    else if (computer == black)
101      fprintf (fp, "[Black \"%s %s\"]\n",PROGRAM,VERSION);
102    else
103      fprintf (fp, "[Black \"%s\"]\n",name);
104 
105    if (pgn_whiteELO)
106      fprintf (fp, "[WhiteELO \"%s\"]\n", NULL2EMPTY(pgn_white));
107    else
108      fprintf(fp, "[WhiteELO \"%d\"]\n",computer==white?myrating:opprating);
109    if (pgn_blackELO)
110      fprintf (fp, "[BlackELO \"%s\"]\n", NULL2EMPTY(pgn_black));
111    else
112      fprintf (fp, "[BlackELO \"%d\"]\n",computer==white?opprating:myrating);
113 
114    if (pgn_result)
115      fprintf (fp, "[Result \"%s\"]\n", pgn_result);
116    else {
117      /* Revive the little-known standard functions! */
118      len = strcspn(resultstr," {");
119      fprintf (fp, "[Result \"%.*s\"]\n", len, resultstr);
120    }
121 
122    if (pgn_othertags) {
123      fprintf (fp, "%s", pgn_othertags);
124    }
125 
126    fprintf (fp, "\n");
127 
128    if (initial_comments)
129    {
130      fprintf(fp, "\n%s\n", initial_comments);
131      /* If it doesn't end in \n, add it */
132      if (initial_comments[0] &&
133          initial_comments[strlen(initial_comments)-1] != '\n')
134         fprintf(fp, "\n");
135    }
136 
137    s[0] = '\0';
138    for (i = 0; i <= GameCnt; i++)
139    {
140       if (! (i % 2)) {
141           char num[6];
142           sprintf(num, "%d. ", i/2 + 1);
143           strcat(s, num);
144       }
145       strcat(s, Game[i].SANmv);
146       strcat(s, " ");
147       if (strlen (s) > 80)
148       {
149          p = s + 79;
150          while (*p-- != ' ');
151          *++p = '\0';
152          fprintf (fp, "%s\n", s);
153          strcpy (s, p+1);
154       }
155       if (Game[i].comments) {
156          fprintf (fp, "%s\n", s);
157          fprintf (fp, "%s", Game[i].comments);
158          if (Game[i].comments[0] &&
159              Game[i].comments[strlen(Game[i].comments)-1] != '\n')
160               fprintf(fp, "\n");
161          s[0] = '\0';
162       }
163    }
164    fprintf (fp, "%s", s);
165    fprintf (fp, "%s", resultstr);
166    fprintf (fp, "\n\n");
167    fclose (fp);
168 
169 }
170 
171 
PGNReadFromFile(const char * file,int showheading)172 void PGNReadFromFile (const char *file, int showheading)
173 /****************************************************************************
174  *
175  *  To read a game from a PGN file.
176  *
177  ****************************************************************************/
178 {
179    FILE *fp;
180 
181    fp = fopen (file, "r");
182    if (fp == NULL)
183    {
184       printf(_("Cannot open file %s\n"), file);
185       return;
186    }
187    yyin = fp;
188 
189    InitVars ();
190 
191    data_dest = DEST_GAME;
192    (void) yylex();
193 
194    fclose (fp);
195 
196    ShowBoard ();
197 
198    if ( showheading ) {
199       printf("\n--------------------------------------------------\n");
200       printf("%s (%s) x %s (%s) - %s\nSite: %s\nDate: %s\n",
201              pgn_white  != NULL ? pgn_white  : "Unknown", pgn_whiteELO != NULL ? pgn_whiteELO : "Unknown",
202              pgn_black  != NULL ? pgn_black  : "Unknown", pgn_blackELO != NULL ? pgn_blackELO : "Unknown",
203              pgn_result != NULL ? pgn_result : "Unknown", pgn_site     != NULL ? pgn_site     : "Unknown",
204              pgn_date   != NULL ? pgn_date   : "Unknown");
205       printf("--------------------------------------------------\n");
206    }
207 }
208 
209 /* Only players in the table below are permitted into the opening book
210    from the PGN files. Please expand the table as needed. Generally,
211    I would recommend only acknowledged GM's and IM's and oneself, but
212    because of the self-changing nature of the book, anything inferior
213    will eventually be eliminated through automatic play as long as
214    you feed the games the program plays back to itself with "book add pgnfile"
215 */
216 /* TODO: Fix this so the list isn't hardcoded. */
217 
218 static const char *const trusted_players[] = {
219   "Alekhine",
220   "Adams",
221   "Anand",
222   "Anderssen",
223   "Andersson",
224   "Aronin",
225   "Averbakh",
226   "Balashov",
227   "Beliavsky",
228   "Benko",
229   "Bernstein",
230   "Bird",
231   "Bogoljubow",
232   "Bolbochan",
233   "Boleslavsky",
234   "Byrne",
235   "Botvinnik",
236   "Bronstein",
237   "Browne",
238   "Capablanca",
239   "Chigorin",
240   "Christiansen",
241   "De Firmian",
242   "Deep Blue",
243   "Deep Thought",
244   "Donner",
245   "Dreev",
246   "Duras",
247   "Euwe",
248   "Evans",
249   "Filip",
250   "Fine",
251   "Fischer",
252   "Flohr",
253   "Furman",
254   "Gelfand",
255   "Geller",
256   "Gereben",
257   "Glek",
258   "Gligoric",
259   "GNU",
260   "Golombek",
261   "Gruenfeld",
262   "Guimard",
263   "Hodgson",
264   "Ivanchuk",
265   "Ivkov",
266   "Janowsky",
267   "Kamsky",
268   "Kan",
269   "Karpov",
270   "Kasparov",
271   "Keres",
272   "Korchnoi",
273   "Kortschnoj",
274   "Kotov",
275   "Kramnik",
276   "Kupreich",
277   "Lasker",
278   "Lautier",
279   "Letelier",
280   "Lilienthal",
281   "Ljubojevic",
282   "Marshall",
283   "Maroczy",
284   "Mieses",
285   "Miles",
286   "Morphy",
287   "Mueller",     /* Every other German has this name... */
288   "Nimzowitsch",
289   "Nunn",
290   "Opocensky",
291   "Pachman",
292   "Petrosian",
293   "Piket",
294   "Pilnik",
295   "Pirc",
296   "Polgar",
297   "Portisch",
298   "Psakhis",
299   "Ragozin",
300   "Reshevsky",
301   "Reti",
302   "Romanish",
303   "Rubinstein",
304   "Saemisch",
305   "Seirawan",
306   "Shirov",
307   "Short",
308   "Silman",
309   "Smyslov",
310   "Sokolsky",
311   "Spassky",
312   "Sveshnikov",
313   "Stahlberg",
314   "Steinitz",
315   "Tal",
316   "Tarjan",
317   "Tartakower",
318   "Timman",
319   "Topalov",
320   "Torre",
321   "Vidmar"
322 
323   };
324 
IsTrustedPlayer(const char * name)325 int IsTrustedPlayer(const char *name)
326 /* Return 1 if name in trusted_players list, else 0 */
327 {
328 	unsigned int i;
329 	for (i = 0; i < (sizeof(trusted_players) / sizeof(*trusted_players));
330 	    	i++) {
331 		if (strstr(name, trusted_players[i]) != NULL)
332 			return 1;
333        }
334 	return 0;
335 }
336