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