fix casting rights after FEN pasting
[xboard.git] / winboard / wclipbrd.c
1 /*\r
2  * wclipbrd.c -- Clipboard routines for WinBoard\r
3  *\r
4  * Copyright 2000,2009 Free Software Foundation, Inc.\r
5  *\r
6  * Enhancements Copyright 2005 Alessandro Scotti\r
7  *\r
8  * ------------------------------------------------------------------------\r
9  *\r
10  * GNU XBoard is free software: you can redistribute it and/or modify\r
11  * it under the terms of the GNU General Public License as published by\r
12  * the Free Software Foundation, either version 3 of the License, or (at\r
13  * your option) any later version.\r
14  *\r
15  * GNU XBoard is distributed in the hope that it will be useful, but\r
16  * WITHOUT ANY WARRANTY; without even the implied warranty of\r
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
18  * General Public License for more details.\r
19  *\r
20  * You should have received a copy of the GNU General Public License\r
21  * along with this program. If not, see http://www.gnu.org/licenses/.  *\r
22  *\r
23  *------------------------------------------------------------------------\r
24  ** See the file ChangeLog for a revision history.  */\r
25 \r
26 #include "config.h"\r
27 \r
28 #include <windows.h>   /* required for all Windows applications */\r
29 #include <stdio.h>\r
30 #include <stdlib.h>\r
31 #include <malloc.h>\r
32 #include <sys/stat.h>\r
33 \r
34 #include "common.h"\r
35 #include "frontend.h"\r
36 #include "backend.h"\r
37 #include "winboard.h"\r
38 #include "wclipbrd.h"\r
39 \r
40 /* Imports from winboard.c */\r
41 extern HWND hwndMain;\r
42 Boolean ParseFEN(Board b, int *stm, char *FEN);\r
43 \r
44 /* File globals */\r
45 static char *copyTemp;\r
46 static char *pasteTemp;\r
47 \r
48 VOID \r
49 CopyFENToClipboard()\r
50 {\r
51   char *fen = NULL;\r
52 \r
53   if(gameMode == EditPosition) EditPositionDone(TRUE); // [HGM] mak sure castling rights are set consistently\r
54   fen = PositionToFEN(currentMove, NULL);\r
55   if (!fen) {\r
56     DisplayError("Unable to convert position to FEN.", 0);\r
57     return;\r
58   }\r
59   if (!CopyTextToClipboard(fen))\r
60       DisplayError("Unable to copy FEN to clipboard.", 0);\r
61   free(fen);\r
62 }\r
63 \r
64 /* [AS] */\r
65 HGLOBAL ExportGameListAsText();\r
66 \r
67 VOID CopyGameListToClipboard()\r
68 {\r
69     HGLOBAL hMem = ExportGameListAsText();\r
70     \r
71     if( hMem != NULL ) {\r
72         /* Assign memory block to clipboard */\r
73         BOOL ok = OpenClipboard( hwndMain );\r
74 \r
75         if( ok ) {\r
76             ok = EmptyClipboard();\r
77 \r
78             if( ok ) {\r
79                 if( hMem != SetClipboardData( CF_TEXT, hMem ) ) {\r
80                     ok = FALSE;\r
81                 }\r
82             }\r
83 \r
84             CloseClipboard();\r
85 \r
86             if( ! ok ) {\r
87                 GlobalFree( hMem );\r
88             }\r
89         }\r
90 \r
91         if( ! ok ) {\r
92             DisplayError( "Cannot copy list to clipboard.", 0 );\r
93         }\r
94     }\r
95 }\r
96 \r
97 VOID\r
98 CopyGameToClipboard()\r
99 {\r
100   /* A rather cheesy hack here. Write the game to a file, then read from the\r
101    * file into the clipboard.\r
102    */\r
103   char *buf = NULL;\r
104   FILE *f;\r
105   unsigned long size;\r
106   size_t len;\r
107   struct stat st;\r
108 \r
109   if (!copyTemp) {\r
110     copyTemp = tempnam(NULL, "wbcp");\r
111   }\r
112   if (!copyTemp) {\r
113       DisplayError("Cannot create temporary file name.",0);\r
114       return;\r
115   }\r
116   f = fopen(copyTemp, "w");\r
117   if (!f) {\r
118     DisplayError("Cannot open temporary file.", 0);\r
119     return;\r
120   }\r
121   if (!SaveGame(f,0,"")) {                      /* call into backend */\r
122     DisplayError("Cannot write to temporary file.", 0);\r
123     goto copy_game_to_clipboard_cleanup;\r
124   }\r
125   f = fopen(copyTemp, "rb");\r
126   if (!f) {\r
127     DisplayError("Cannot reopen temporary file.", 0);\r
128     goto copy_game_to_clipboard_cleanup;\r
129   }\r
130   if (fstat(fileno(f), &st) < 0) {\r
131     DisplayError("Cannot determine size of file.", 0);\r
132     goto copy_game_to_clipboard_cleanup;\r
133   }\r
134   size = st.st_size;\r
135   if (size == -1) {\r
136     DisplayError("Cannot determine size of file.", 0);\r
137     goto copy_game_to_clipboard_cleanup;\r
138   }\r
139   rewind(f);\r
140   buf = (char*)malloc(size+1);\r
141   if (!buf) {\r
142     DisplayError("Cannot allocate clipboard buffer.", 0);\r
143     goto copy_game_to_clipboard_cleanup;\r
144   }\r
145   len = fread(buf, sizeof(char), size, f);\r
146   if (len == -1) {\r
147     DisplayError("Cannot read from temporary file.", 0);\r
148     goto copy_game_to_clipboard_cleanup;\r
149   }\r
150   if ((unsigned long)size != (unsigned long)len) { /* sigh */ \r
151       DisplayError("Error reading from temporary file.", 0);\r
152       goto copy_game_to_clipboard_cleanup;\r
153   }\r
154   buf[size] = 0;\r
155   if (!CopyTextToClipboard(buf)) {\r
156       DisplayError("Cannot copy text to clipboard", 0);\r
157   }\r
158 \r
159 copy_game_to_clipboard_cleanup:\r
160   if (buf) free(buf);\r
161   if (f) fclose(f);\r
162 }\r
163 \r
164 \r
165 int \r
166 CopyTextToClipboard(char *text)\r
167 {\r
168   /* some (most?) of the error checking may be overkill, \r
169    * but hey, this is Windows \r
170    */\r
171   HGLOBAL hGlobalMem;\r
172   LPVOID lpGlobalMem;\r
173   BOOL locked;\r
174   UINT lockCount;\r
175   DWORD err;\r
176 \r
177   hGlobalMem = GlobalAlloc(GHND, (DWORD)lstrlen(text)+1);\r
178   if (hGlobalMem == NULL) {\r
179     DisplayError("Unable to allocate memory for clipboard.", 0);\r
180     return FALSE;\r
181   }\r
182   lpGlobalMem = GlobalLock(hGlobalMem);\r
183   if (lpGlobalMem == NULL) {\r
184     DisplayError("Unable to lock clipboard memory.", 0);\r
185     GlobalFree(hGlobalMem);\r
186     return FALSE;\r
187   }\r
188   lstrcpy(lpGlobalMem, text);\r
189   if (appData.debugMode) {\r
190     lockCount = GlobalFlags(hGlobalMem) & GMEM_LOCKCOUNT;\r
191     fprintf(debugFP, "CopyTextToClipboard(): lock count %d\n", lockCount);\r
192   }\r
193   SetLastError(NO_ERROR);\r
194   locked = GlobalUnlock(hGlobalMem);\r
195   err = GetLastError();\r
196   if (appData.debugMode) {\r
197     lockCount = GlobalFlags(hGlobalMem) & GMEM_LOCKCOUNT;\r
198     fprintf(debugFP, "CopyTextToClipboard(): lock count %d\n", lockCount);\r
199   }\r
200   if (!locked) {\r
201     locked = !((err == NO_ERROR) || (err == ERROR_NOT_LOCKED));\r
202     if (appData.debugMode) {\r
203       fprintf(debugFP, \r
204               "CopyTextToClipboard(): err %d locked %d\n", (int)err, locked);\r
205     }\r
206   }\r
207   if (locked) {\r
208     DisplayError("Cannot unlock clipboard memory.", 0);\r
209     GlobalFree(hGlobalMem);\r
210     return FALSE;\r
211   }\r
212   if (!OpenClipboard(hwndMain)) {\r
213     DisplayError("Cannot open clipboard.", 0);\r
214     GlobalFree(hGlobalMem);\r
215     return FALSE;\r
216   }\r
217   if (!EmptyClipboard()) {\r
218     DisplayError("Cannot empty clipboard.", 0);\r
219     return FALSE;\r
220   }\r
221   if (hGlobalMem != SetClipboardData(CF_TEXT, hGlobalMem)) {\r
222     DisplayError("Cannot copy text to clipboard.", 0);\r
223     CloseClipboard();\r
224     GlobalFree(hGlobalMem);\r
225     return FALSE;\r
226   }\r
227   if (!CloseClipboard())\r
228     DisplayError("Cannot close clipboard.", 0);\r
229   \r
230   return TRUE;\r
231 }\r
232 \r
233 /* [AS] Reworked paste functions so they can work with strings too */\r
234 \r
235 VOID PasteFENFromString( char * fen )\r
236 {\r
237   if (appData.debugMode) {\r
238     fprintf(debugFP, "PasteFenFromString(): fen '%s'\n", fen);\r
239   }\r
240   EditPositionPasteFEN(fen); /* call into backend */\r
241   free(fen);\r
242 }\r
243 \r
244 \r
245 VOID\r
246 PasteFENFromClipboard()\r
247 {\r
248   char *fen = NULL;\r
249   if (!PasteTextFromClipboard(&fen)) {\r
250       DisplayError("Unable to paste FEN from clipboard.", 0);\r
251       return;\r
252   }\r
253   PasteFENFromString( fen );\r
254 }\r
255 \r
256 VOID PasteGameFromString( char * buf )\r
257 {\r
258   FILE *f;\r
259   size_t len;\r
260   if (!pasteTemp) {\r
261     pasteTemp = tempnam(NULL, "wbpt");\r
262   }\r
263   f = fopen(pasteTemp, "w");\r
264   if (!f) {\r
265     DisplayError("Unable to create temporary file.", 0);\r
266     free(buf); /* [AS] */\r
267     return;\r
268   }\r
269   len = fwrite(buf, sizeof(char), strlen(buf), f);\r
270   fclose(f);\r
271   if (len != strlen(buf)) {\r
272     DisplayError("Error writing to temporary file.", 0);\r
273     free(buf); /* [AS] */\r
274     return;\r
275   }\r
276   LoadGameFromFile(pasteTemp, 0, "Clipboard", TRUE);\r
277   free( buf ); /* [AS] */\r
278 }\r
279 \r
280 \r
281 VOID\r
282 PasteGameFromClipboard()\r
283 {\r
284   /* Write the clipboard to a temp file, then let LoadGameFromFile()\r
285    * do all the work.  */\r
286   char *buf;\r
287   if (!PasteTextFromClipboard(&buf)) {\r
288     return;\r
289   }\r
290   PasteGameFromString( buf );\r
291 }\r
292 \r
293 /* [AS] Try to detect whether the clipboard contains FEN or PGN data */\r
294 VOID PasteGameOrFENFromClipboard()\r
295 {\r
296   char *buf;\r
297 //  char *tmp;\r
298   Board dummyBoard; int dummy; // [HGM] paste any\r
299 \r
300   if (!PasteTextFromClipboard(&buf)) {\r
301     return;\r
302   }\r
303 \r
304   // [HGM] paste any: make still smarter, to allow pasting of games without tags, recognize FEN in stead\r
305   if(!ParseFEN(dummyBoard, &dummy, buf) ) {\r
306       PasteGameFromString( buf );\r
307   }\r
308   else {\r
309       PasteFENFromString( buf );\r
310   }\r
311 }\r
312 \r
313 int \r
314 PasteTextFromClipboard(char **text)\r
315 {\r
316   /* some (most?) of the error checking may be overkill, \r
317    * but hey, this is Windows \r
318    */\r
319   HANDLE hClipMem;\r
320   LPVOID lpClipMem;\r
321   BOOL locked = FALSE;\r
322   DWORD err;\r
323   UINT lockCount;\r
324 \r
325   if (!OpenClipboard(hwndMain)) {\r
326     DisplayError("Unable to open clipboard.", 0);\r
327     return FALSE;\r
328   }\r
329   hClipMem = GetClipboardData(CF_TEXT);\r
330   if (hClipMem == NULL) {\r
331     CloseClipboard();\r
332     DisplayError("No text in clipboard.", 0);\r
333     return FALSE;\r
334   }\r
335   lpClipMem = GlobalLock(hClipMem);\r
336   if (lpClipMem == NULL) {\r
337     CloseClipboard();\r
338     DisplayError("Unable to lock clipboard memory.", 0);\r
339     return FALSE;\r
340   }\r
341   *text = (char *) malloc(GlobalSize(hClipMem)+1);\r
342   if (!*text) {\r
343     DisplayError("Unable to allocate memory for text string.", 0);\r
344     CloseClipboard();\r
345     return FALSE;\r
346   }\r
347   lstrcpy(*text, lpClipMem);\r
348   if (appData.debugMode) {\r
349     lockCount = GlobalFlags(hClipMem) & GMEM_LOCKCOUNT;\r
350     fprintf(debugFP, "PasteTextFromClipboard(): lock count %d\n", lockCount);\r
351   }\r
352   SetLastError(NO_ERROR);\r
353   /*suggested by Wilkin Ng*/\r
354   lockCount = GlobalFlags(hClipMem) & GMEM_LOCKCOUNT;\r
355   if (lockCount) {\r
356     locked = GlobalUnlock(hClipMem);\r
357   }\r
358   err = GetLastError();\r
359   if (appData.debugMode) {\r
360     lockCount = GlobalFlags(hClipMem) & GMEM_LOCKCOUNT;\r
361     fprintf(debugFP, "PasteTextFromClipboard(): lock count %d\n", lockCount);\r
362   }\r
363   if (!locked) {\r
364     locked = !((err == NO_ERROR) || (err == ERROR_NOT_LOCKED));\r
365     if (appData.debugMode) {\r
366       fprintf(debugFP, \r
367               "PasteTextFromClipboard(): err %d locked %d\n", (int)err, locked);\r
368     }\r
369   }\r
370   if (locked) \r
371     DisplayError("Unable to unlock clipboard memory.", 0);\r
372   \r
373   if (!CloseClipboard())\r
374     DisplayError("Unable to close clipboard.", 0);\r
375   \r
376   return TRUE;\r
377 }\r
378 \r
379 VOID\r
380 DeleteClipboardTempFiles()\r
381 {\r
382   if (copyTemp) remove(copyTemp);\r
383   if (pasteTemp) remove(pasteTemp);\r
384 }\r