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