fix for bug #27826: fixed autoDisplayComment
[xboard.git] / winboard / winboard.c
1 /*\r
2  * WinBoard.c -- Windows NT front end to XBoard\r
3  *\r
4  * Copyright 1991 by Digital Equipment Corporation, Maynard,\r
5  * Massachusetts. \r
6  *\r
7  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,\r
8  * 2007, 2008, 2009 Free Software Foundation, Inc.\r
9  *\r
10  * Enhancements Copyright 2005 Alessandro Scotti\r
11  *\r
12  * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,\r
13  * which was written and is copyrighted by Wayne Christopher.\r
14  *\r
15  * The following terms apply to Digital Equipment Corporation's copyright\r
16  * interest in XBoard:\r
17  * ------------------------------------------------------------------------\r
18  * All Rights Reserved\r
19  *\r
20  * Permission to use, copy, modify, and distribute this software and its\r
21  * documentation for any purpose and without fee is hereby granted,\r
22  * provided that the above copyright notice appear in all copies and that\r
23  * both that copyright notice and this permission notice appear in\r
24  * supporting documentation, and that the name of Digital not be\r
25  * used in advertising or publicity pertaining to distribution of the\r
26  * software without specific, written prior permission.\r
27  *\r
28  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
29  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL\r
30  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
31  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\r
32  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\r
33  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS\r
34  * SOFTWARE.\r
35  * ------------------------------------------------------------------------\r
36  *\r
37  * The following terms apply to the enhanced version of XBoard\r
38  * distributed by the Free Software Foundation:\r
39  * ------------------------------------------------------------------------\r
40  *\r
41  * GNU XBoard is free software: you can redistribute it and/or modify\r
42  * it under the terms of the GNU General Public License as published by\r
43  * the Free Software Foundation, either version 3 of the License, or (at\r
44  * your option) any later version.\r
45  *\r
46  * GNU XBoard is distributed in the hope that it will be useful, but\r
47  * WITHOUT ANY WARRANTY; without even the implied warranty of\r
48  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
49  * General Public License for more details.\r
50  *\r
51  * You should have received a copy of the GNU General Public License\r
52  * along with this program. If not, see http://www.gnu.org/licenses/.  *\r
53  *\r
54  *------------------------------------------------------------------------\r
55  ** See the file ChangeLog for a revision history.  */\r
56 \r
57 #include "config.h"\r
58 \r
59 #include <windows.h>\r
60 #include <winuser.h>\r
61 #include <winsock.h>\r
62 #include <commctrl.h>\r
63 \r
64 #include <stdio.h>\r
65 #include <stdlib.h>\r
66 #include <time.h>\r
67 #include <malloc.h>\r
68 #include <sys/stat.h>\r
69 #include <fcntl.h>\r
70 #include <math.h>\r
71 #include <commdlg.h>\r
72 #include <dlgs.h>\r
73 #include <richedit.h>\r
74 #include <mmsystem.h>\r
75 #include <ctype.h>\r
76 \r
77 #if __GNUC__\r
78 #include <errno.h>\r
79 #include <string.h>\r
80 #endif\r
81 \r
82 #include "common.h"\r
83 #include "winboard.h"\r
84 #include "frontend.h"\r
85 #include "backend.h"\r
86 #include "moves.h"\r
87 #include "wclipbrd.h"\r
88 #include "wgamelist.h"\r
89 #include "wedittags.h"\r
90 #include "woptions.h"\r
91 #include "wsockerr.h"\r
92 #include "defaults.h"\r
93 #include "help.h"\r
94 #include "wsnap.h"\r
95 \r
96 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );\r
97 \r
98   int myrandom(void);\r
99   void mysrandom(unsigned int seed);\r
100 \r
101 extern int whiteFlag, blackFlag;\r
102 Boolean flipClock = FALSE;\r
103 extern HANDLE chatHandle[];\r
104 extern int ics_type;\r
105 \r
106 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);\r
107 VOID NewVariantPopup(HWND hwnd);\r
108 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,\r
109                    /*char*/int promoChar));\r
110 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);\r
111 void DisplayMove P((int moveNumber));\r
112 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));\r
113 void ChatPopUp P(());\r
114 typedef struct {\r
115   ChessSquare piece;  \r
116   POINT pos;      /* window coordinates of current pos */\r
117   POINT lastpos;  /* window coordinates of last pos - used for clipping */\r
118   POINT from;     /* board coordinates of the piece's orig pos */\r
119   POINT to;       /* board coordinates of the piece's new pos */\r
120 } AnimInfo;\r
121 \r
122 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };\r
123 \r
124 typedef struct {\r
125   POINT start;    /* window coordinates of start pos */\r
126   POINT pos;      /* window coordinates of current pos */\r
127   POINT lastpos;  /* window coordinates of last pos - used for clipping */\r
128   POINT from;     /* board coordinates of the piece's orig pos */\r
129 } DragInfo;\r
130 \r
131 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };\r
132 \r
133 typedef struct {\r
134   POINT sq[2];    /* board coordinates of from, to squares */\r
135 } HighlightInfo;\r
136 \r
137 static HighlightInfo highlightInfo        = { {{-1, -1}, {-1, -1}} };\r
138 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };\r
139 \r
140 typedef struct { // [HGM] atomic\r
141   int fromX, fromY, toX, toY, radius;\r
142 } ExplodeInfo;\r
143 \r
144 static ExplodeInfo explodeInfo;\r
145 \r
146 /* Window class names */\r
147 char szAppName[] = "WinBoard";\r
148 char szConsoleName[] = "WBConsole";\r
149 \r
150 /* Title bar text */\r
151 char szTitle[] = "WinBoard";\r
152 char szConsoleTitle[] = "I C S Interaction";\r
153 \r
154 char *programName;\r
155 char *settingsFileName;\r
156 BOOLEAN saveSettingsOnExit;\r
157 char installDir[MSG_SIZ];\r
158 \r
159 BoardSize boardSize;\r
160 BOOLEAN chessProgram;\r
161 static int boardX, boardY;\r
162 int  minX, minY; // [HGM] placement: volatile limits on upper-left corner\r
163 static int squareSize, lineGap, minorSize;\r
164 static int winWidth, winHeight, winW, winH;\r
165 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo\r
166 static int logoHeight = 0;\r
167 static char messageText[MESSAGE_TEXT_MAX];\r
168 static int clockTimerEvent = 0;\r
169 static int loadGameTimerEvent = 0;\r
170 static int analysisTimerEvent = 0;\r
171 static DelayedEventCallback delayedTimerCallback;\r
172 static int delayedTimerEvent = 0;\r
173 static int buttonCount = 2;\r
174 char *icsTextMenuString;\r
175 char *icsNames;\r
176 char *firstChessProgramNames;\r
177 char *secondChessProgramNames;\r
178 \r
179 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */\r
180 \r
181 #define PALETTESIZE 256\r
182 \r
183 HINSTANCE hInst;          /* current instance */\r
184 HWND hwndMain = NULL;        /* root window*/\r
185 HWND hwndConsole = NULL;\r
186 BOOLEAN alwaysOnTop = FALSE;\r
187 RECT boardRect;\r
188 COLORREF lightSquareColor, darkSquareColor, whitePieceColor, \r
189   blackPieceColor, highlightSquareColor, premoveHighlightColor;\r
190 HPALETTE hPal;\r
191 ColorClass currentColorClass;\r
192 \r
193 HWND hCommPort = NULL;    /* currently open comm port */\r
194 static HWND hwndPause;    /* pause button */\r
195 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */\r
196 static HBRUSH lightSquareBrush, darkSquareBrush,\r
197   blackSquareBrush, /* [HGM] for band between board and holdings */\r
198   explodeBrush,     /* [HGM] atomic */\r
199   whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;\r
200 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];\r
201 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];\r
202 static HPEN gridPen = NULL;\r
203 static HPEN highlightPen = NULL;\r
204 static HPEN premovePen = NULL;\r
205 static NPLOGPALETTE pLogPal;\r
206 static BOOL paletteChanged = FALSE;\r
207 static HICON iconWhite, iconBlack, iconCurrent;\r
208 static int doingSizing = FALSE;\r
209 static int lastSizing = 0;\r
210 static int prevStderrPort;\r
211 static HBITMAP userLogo;\r
212 \r
213 /* [AS] Support for background textures */\r
214 #define BACK_TEXTURE_MODE_DISABLED      0\r
215 #define BACK_TEXTURE_MODE_PLAIN         1\r
216 #define BACK_TEXTURE_MODE_FULL_RANDOM   2\r
217 \r
218 static HBITMAP liteBackTexture = NULL;\r
219 static HBITMAP darkBackTexture = NULL;\r
220 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
221 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
222 static int backTextureSquareSize = 0;\r
223 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];\r
224 \r
225 #if __GNUC__ && !defined(_winmajor)\r
226 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */\r
227 #else\r
228 #if defined(_winmajor)\r
229 #define oldDialog (_winmajor < 4)\r
230 #else\r
231 #define oldDialog 0\r
232 #endif\r
233 #endif\r
234 \r
235 char *defaultTextAttribs[] = \r
236 {\r
237   COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,\r
238   COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,\r
239   COLOR_NONE\r
240 };\r
241 \r
242 typedef struct {\r
243   char *name;\r
244   int squareSize;\r
245   int lineGap;\r
246   int smallLayout;\r
247   int tinyLayout;\r
248   int cliWidth, cliHeight;\r
249 } SizeInfo;\r
250 \r
251 SizeInfo sizeInfo[] = \r
252 {\r
253   { "tiny",     21, 0, 1, 1, 0, 0 },\r
254   { "teeny",    25, 1, 1, 1, 0, 0 },\r
255   { "dinky",    29, 1, 1, 1, 0, 0 },\r
256   { "petite",   33, 1, 1, 1, 0, 0 },\r
257   { "slim",     37, 2, 1, 0, 0, 0 },\r
258   { "small",    40, 2, 1, 0, 0, 0 },\r
259   { "mediocre", 45, 2, 1, 0, 0, 0 },\r
260   { "middling", 49, 2, 0, 0, 0, 0 },\r
261   { "average",  54, 2, 0, 0, 0, 0 },\r
262   { "moderate", 58, 3, 0, 0, 0, 0 },\r
263   { "medium",   64, 3, 0, 0, 0, 0 },\r
264   { "bulky",    72, 3, 0, 0, 0, 0 },\r
265   { "large",    80, 3, 0, 0, 0, 0 },\r
266   { "big",      87, 3, 0, 0, 0, 0 },\r
267   { "huge",     95, 3, 0, 0, 0, 0 },\r
268   { "giant",    108, 3, 0, 0, 0, 0 },\r
269   { "colossal", 116, 4, 0, 0, 0, 0 },\r
270   { "titanic",  129, 4, 0, 0, 0, 0 },\r
271   { NULL, 0, 0, 0, 0, 0, 0 }\r
272 };\r
273 \r
274 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}\r
275 MyFont fontRec[NUM_SIZES][NUM_FONTS] =\r
276 {\r
277   { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },\r
278   { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },\r
279   { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },\r
280   { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },\r
281   { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },\r
282   { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },\r
283   { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },\r
284   { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },\r
285   { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },\r
286   { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },\r
287   { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },\r
288   { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },\r
289   { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },\r
290   { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },\r
291   { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },\r
292   { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },\r
293   { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },\r
294   { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },\r
295 };\r
296 \r
297 MyFont *font[NUM_SIZES][NUM_FONTS];\r
298 \r
299 typedef struct {\r
300   char *label;\r
301   int id;\r
302   HWND hwnd;\r
303   WNDPROC wndproc;\r
304 } MyButtonDesc;\r
305 \r
306 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)\r
307 #define N_BUTTONS 5\r
308 \r
309 MyButtonDesc buttonDesc[N_BUTTONS] =\r
310 {\r
311   {"<<", IDM_ToStart, NULL, NULL},\r
312   {"<", IDM_Backward, NULL, NULL},\r
313   {"P", IDM_Pause, NULL, NULL},\r
314   {">", IDM_Forward, NULL, NULL},\r
315   {">>", IDM_ToEnd, NULL, NULL},\r
316 };\r
317 \r
318 int tinyLayout = 0, smallLayout = 0;\r
319 #define MENU_BAR_ITEMS 7\r
320 char *menuBarText[2][MENU_BAR_ITEMS+1] = {\r
321   { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },\r
322   { "&F", "&M", "&A", "&S", "&O", "&H", NULL },\r
323 };\r
324 \r
325 \r
326 MySound sounds[(int)NSoundClasses];\r
327 MyTextAttribs textAttribs[(int)NColorClasses];\r
328 \r
329 MyColorizeAttribs colorizeAttribs[] = {\r
330   { (COLORREF)0, 0, "Shout Text" },\r
331   { (COLORREF)0, 0, "SShout/CShout" },\r
332   { (COLORREF)0, 0, "Channel 1 Text" },\r
333   { (COLORREF)0, 0, "Channel Text" },\r
334   { (COLORREF)0, 0, "Kibitz Text" },\r
335   { (COLORREF)0, 0, "Tell Text" },\r
336   { (COLORREF)0, 0, "Challenge Text" },\r
337   { (COLORREF)0, 0, "Request Text" },\r
338   { (COLORREF)0, 0, "Seek Text" },\r
339   { (COLORREF)0, 0, "Normal Text" },\r
340   { (COLORREF)0, 0, "None" }\r
341 };\r
342 \r
343 \r
344 \r
345 static char *commentTitle;\r
346 static char *commentText;\r
347 static int commentIndex;\r
348 static Boolean editComment = FALSE;\r
349 HWND commentDialog = NULL;\r
350 int commentUp = FALSE;\r
351 static int commentX, commentY, commentH, commentW;\r
352 \r
353 static char *analysisTitle;\r
354 static char *analysisText;\r
355 HWND analysisDialog = NULL;\r
356 BOOLEAN analysisDialogUp = FALSE;\r
357 static int analysisX, analysisY, analysisH, analysisW;\r
358 \r
359 char errorTitle[MSG_SIZ];\r
360 char errorMessage[2*MSG_SIZ];\r
361 HWND errorDialog = NULL;\r
362 BOOLEAN moveErrorMessageUp = FALSE;\r
363 BOOLEAN consoleEcho = TRUE;\r
364 CHARFORMAT consoleCF;\r
365 COLORREF consoleBackgroundColor;\r
366 \r
367 char *programVersion;\r
368 \r
369 #define CPReal 1\r
370 #define CPComm 2\r
371 #define CPSock 3\r
372 #define CPRcmd 4\r
373 typedef int CPKind;\r
374 \r
375 typedef struct {\r
376   CPKind kind;\r
377   HANDLE hProcess;\r
378   DWORD pid;\r
379   HANDLE hTo;\r
380   HANDLE hFrom;\r
381   SOCKET sock;\r
382   SOCKET sock2;  /* stderr socket for OpenRcmd */\r
383 } ChildProc;\r
384 \r
385 #define INPUT_SOURCE_BUF_SIZE 4096\r
386 \r
387 typedef struct _InputSource {\r
388   CPKind kind;\r
389   HANDLE hFile;\r
390   SOCKET sock;\r
391   int lineByLine;\r
392   HANDLE hThread;\r
393   DWORD id;\r
394   char buf[INPUT_SOURCE_BUF_SIZE];\r
395   char *next;\r
396   DWORD count;\r
397   int error;\r
398   InputCallback func;\r
399   struct _InputSource *second;  /* for stderr thread on CPRcmd */\r
400   VOIDSTAR closure;\r
401 } InputSource;\r
402 \r
403 InputSource *consoleInputSource;\r
404 \r
405 DCB dcb;\r
406 \r
407 /* forward */\r
408 VOID ConsoleOutput(char* data, int length, int forceVisible);\r
409 VOID ConsoleCreate();\r
410 LRESULT CALLBACK\r
411   ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);\r
412 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);\r
413 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);\r
414 VOID ParseCommSettings(char *arg, DCB *dcb);\r
415 LRESULT CALLBACK\r
416   StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);\r
417 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);\r
418 void ParseIcsTextMenu(char *icsTextMenuString);\r
419 VOID PopUpMoveDialog(char firstchar);\r
420 VOID PopUpNameDialog(char firstchar);\r
421 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);\r
422 \r
423 /* [AS] */\r
424 int NewGameFRC();\r
425 int GameListOptions();\r
426 \r
427 HWND moveHistoryDialog = NULL;\r
428 BOOLEAN moveHistoryDialogUp = FALSE;\r
429 \r
430 WindowPlacement wpMoveHistory;\r
431 \r
432 HWND evalGraphDialog = NULL;\r
433 BOOLEAN evalGraphDialogUp = FALSE;\r
434 \r
435 WindowPlacement wpEvalGraph;\r
436 \r
437 HWND engineOutputDialog = NULL;\r
438 BOOLEAN engineOutputDialogUp = FALSE;\r
439 \r
440 WindowPlacement wpEngineOutput;\r
441 WindowPlacement wpGameList;\r
442 WindowPlacement wpConsole;\r
443 \r
444 VOID MoveHistoryPopUp();\r
445 VOID MoveHistoryPopDown();\r
446 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );\r
447 BOOL MoveHistoryIsUp();\r
448 \r
449 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );\r
450 VOID EvalGraphPopUp();\r
451 VOID EvalGraphPopDown();\r
452 BOOL EvalGraphIsUp();\r
453 \r
454 VOID EngineOutputPopUp();\r
455 VOID EngineOutputPopDown();\r
456 BOOL EngineOutputIsUp();\r
457 VOID EngineOutputUpdate( FrontEndProgramStats * stats );\r
458 \r
459 VOID EngineOptionsPopup(); // [HGM] settings\r
460 \r
461 VOID GothicPopUp(char *title, VariantClass variant);\r
462 /*\r
463  * Setting "frozen" should disable all user input other than deleting\r
464  * the window.  We do this while engines are initializing themselves.\r
465  */\r
466 static int frozen = 0;\r
467 static int oldMenuItemState[MENU_BAR_ITEMS];\r
468 void FreezeUI()\r
469 {\r
470   HMENU hmenu;\r
471   int i;\r
472 \r
473   if (frozen) return;\r
474   frozen = 1;\r
475   hmenu = GetMenu(hwndMain);\r
476   for (i=0; i<MENU_BAR_ITEMS; i++) {\r
477     oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);\r
478   }\r
479   DrawMenuBar(hwndMain);\r
480 }\r
481 \r
482 /* Undo a FreezeUI */\r
483 void ThawUI()\r
484 {\r
485   HMENU hmenu;\r
486   int i;\r
487 \r
488   if (!frozen) return;\r
489   frozen = 0;\r
490   hmenu = GetMenu(hwndMain);\r
491   for (i=0; i<MENU_BAR_ITEMS; i++) {\r
492     EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);\r
493   }\r
494   DrawMenuBar(hwndMain);\r
495 }\r
496 \r
497 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them\r
498 \r
499 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */\r
500 #ifdef JAWS\r
501 #include "jaws.c"\r
502 #else\r
503 #define JAWS_INIT\r
504 #define JAWS_ARGS\r
505 #define JAWS_ALT_INTERCEPT\r
506 #define JAWS_KB_NAVIGATION\r
507 #define JAWS_MENU_ITEMS\r
508 #define JAWS_SILENCE\r
509 #define JAWS_REPLAY\r
510 #define JAWS_ACCEL\r
511 #define JAWS_COPYRIGHT\r
512 #define JAWS_DELETE(X) X\r
513 #define SAYMACHINEMOVE()\r
514 #define SAY(X)\r
515 #endif\r
516 \r
517 /*---------------------------------------------------------------------------*\\r
518  *\r
519  * WinMain\r
520  *\r
521 \*---------------------------------------------------------------------------*/\r
522 \r
523 int APIENTRY\r
524 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,\r
525         LPSTR lpCmdLine, int nCmdShow)\r
526 {\r
527   MSG msg;\r
528   HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;\r
529 //  INITCOMMONCONTROLSEX ex;\r
530 \r
531   debugFP = stderr;\r
532 \r
533   LoadLibrary("RICHED32.DLL");\r
534   consoleCF.cbSize = sizeof(CHARFORMAT);\r
535 \r
536   if (!InitApplication(hInstance)) {\r
537     return (FALSE);\r
538   }\r
539   if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {\r
540     return (FALSE);\r
541   }\r
542 \r
543   JAWS_INIT\r
544 \r
545 //  InitCommonControlsEx(&ex);\r
546   InitCommonControls();\r
547 \r
548   hAccelMain = LoadAccelerators (hInstance, szAppName);\r
549   hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");\r
550   hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */\r
551 \r
552   /* Acquire and dispatch messages until a WM_QUIT message is received. */\r
553 \r
554   while (GetMessage(&msg, /* message structure */\r
555                     NULL, /* handle of window receiving the message */\r
556                     0,    /* lowest message to examine */\r
557                     0))   /* highest message to examine */\r
558     {\r
559 \r
560       if(msg.message == WM_CHAR && msg.wParam == '\t') {\r
561         // [HGM] navigate: switch between all windows with tab\r
562         HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;\r
563         int i, currentElement = 0;\r
564 \r
565         // first determine what element of the chain we come from (if any)\r
566         if(appData.icsActive) {\r
567             hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);\r
568             hText  = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
569         }\r
570         if(engineOutputDialog && EngineOutputIsUp()) {\r
571             e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);\r
572             e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);\r
573         }\r
574         if(moveHistoryDialog && MoveHistoryIsUp()) {\r
575             mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);\r
576         }\r
577         if(msg.hwnd == hwndMain) currentElement = 7 ; else\r
578         if(msg.hwnd == engineOutputDialog) currentElement = 2; else\r
579         if(msg.hwnd == e1)                 currentElement = 2; else\r
580         if(msg.hwnd == e2)                 currentElement = 3; else\r
581         if(msg.hwnd == moveHistoryDialog) currentElement = 4; else\r
582         if(msg.hwnd == mh)                currentElement = 4; else\r
583         if(msg.hwnd == evalGraphDialog)    currentElement = 6; else\r
584         if(msg.hwnd == hText)  currentElement = 5; else\r
585         if(msg.hwnd == hInput) currentElement = 6; else\r
586         for (i = 0; i < N_BUTTONS; i++) {\r
587             if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }\r
588         }\r
589 \r
590         // determine where to go to\r
591         if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;\r
592           do {\r
593             currentElement = (currentElement + direction) % 7;\r
594             switch(currentElement) {\r
595                 case 0:\r
596                   h = hwndMain; break; // passing this case always makes the loop exit\r
597                 case 1:\r
598                   h = buttonDesc[0].hwnd; break; // could be NULL\r
599                 case 2:\r
600                   if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows\r
601                   h = e1; break;\r
602                 case 3:\r
603                   if(!EngineOutputIsUp()) continue;\r
604                   h = e2; break;\r
605                 case 4:\r
606                   if(!MoveHistoryIsUp()) continue;\r
607                   h = mh; break;\r
608 //              case 6: // input to eval graph does not seem to get here!\r
609 //                if(!EvalGraphIsUp()) continue;\r
610 //                h = evalGraphDialog; break;\r
611                 case 5:\r
612                   if(!appData.icsActive) continue;\r
613                   SAY("display");\r
614                   h = hText; break;\r
615                 case 6:\r
616                   if(!appData.icsActive) continue;\r
617                   SAY("input");\r
618                   h = hInput; break;\r
619             }\r
620           } while(h == 0);\r
621 \r
622           if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);\r
623           if(currentElement < 5 && IsIconic(hwndMain))    ShowWindow(hwndMain, SW_RESTORE); // all open together\r
624           SetFocus(h);\r
625 \r
626           continue; // this message now has been processed\r
627         }\r
628       }\r
629 \r
630       if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&\r
631           !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&\r
632           !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&\r
633           !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&\r
634           !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&\r
635           !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&\r
636           !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&\r
637           !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL\r
638           !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&\r
639           !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {\r
640         int done = 0, i; // [HGM] chat: dispatch cat-box messages\r
641         for(i=0; i<MAX_CHAT; i++) \r
642             if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {\r
643                 done = 1; break;\r
644         }\r
645         if(done) continue; // [HGM] chat: end patch\r
646         TranslateMessage(&msg); /* Translates virtual key codes */\r
647         DispatchMessage(&msg);  /* Dispatches message to window */\r
648       }\r
649     }\r
650 \r
651 \r
652   return (msg.wParam);  /* Returns the value from PostQuitMessage */\r
653 }\r
654 \r
655 /*---------------------------------------------------------------------------*\\r
656  *\r
657  * Initialization functions\r
658  *\r
659 \*---------------------------------------------------------------------------*/\r
660 \r
661 void\r
662 SetUserLogo()\r
663 {   // update user logo if necessary\r
664     static char oldUserName[MSG_SIZ], *curName;\r
665 \r
666     if(appData.autoLogo) {\r
667           curName = UserName();\r
668           if(strcmp(curName, oldUserName)) {\r
669                 sprintf(oldUserName, "logos\\%s.bmp", curName);\r
670                 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );    \r
671                 strcpy(oldUserName, curName);\r
672           }\r
673     }\r
674 }\r
675 \r
676 BOOL\r
677 InitApplication(HINSTANCE hInstance)\r
678 {\r
679   WNDCLASS wc;\r
680 \r
681   /* Fill in window class structure with parameters that describe the */\r
682   /* main window. */\r
683 \r
684   wc.style         = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */\r
685   wc.lpfnWndProc   = (WNDPROC)WndProc;  /* Window Procedure */\r
686   wc.cbClsExtra    = 0;                 /* No per-class extra data. */\r
687   wc.cbWndExtra    = 0;                 /* No per-window extra data. */\r
688   wc.hInstance     = hInstance;         /* Owner of this class */\r
689   wc.hIcon         = LoadIcon(hInstance, "icon_white");\r
690   wc.hCursor       = LoadCursor(NULL, IDC_ARROW);       /* Cursor */\r
691   wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);  /* Default color */\r
692   wc.lpszMenuName  = szAppName;                 /* Menu name from .RC */\r
693   wc.lpszClassName = szAppName;                 /* Name to register as */\r
694 \r
695   /* Register the window class and return success/failure code. */\r
696   if (!RegisterClass(&wc)) return FALSE;\r
697 \r
698   wc.style         = CS_HREDRAW | CS_VREDRAW;\r
699   wc.lpfnWndProc   = (WNDPROC)ConsoleWndProc;\r
700   wc.cbClsExtra    = 0;\r
701   wc.cbWndExtra    = DLGWINDOWEXTRA;\r
702   wc.hInstance     = hInstance;\r
703   wc.hIcon         = LoadIcon(hInstance, "icon_white");\r
704   wc.hCursor       = LoadCursor(NULL, IDC_ARROW);\r
705   wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);\r
706   wc.lpszMenuName  = NULL;\r
707   wc.lpszClassName = szConsoleName;\r
708 \r
709   if (!RegisterClass(&wc)) return FALSE;\r
710   return TRUE;\r
711 }\r
712 \r
713 \r
714 /* Set by InitInstance, used by EnsureOnScreen */\r
715 int screenHeight, screenWidth;\r
716 \r
717 void\r
718 EnsureOnScreen(int *x, int *y, int minX, int minY)\r
719 {\r
720 //  int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);\r
721   /* Be sure window at (x,y) is not off screen (or even mostly off screen) */\r
722   if (*x > screenWidth - 32) *x = 0;\r
723   if (*y > screenHeight - 32) *y = 0;\r
724   if (*x < minX) *x = minX;\r
725   if (*y < minY) *y = minY;\r
726 }\r
727 \r
728 BOOL\r
729 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)\r
730 {\r
731   HWND hwnd; /* Main window handle. */\r
732   int ibs;\r
733   WINDOWPLACEMENT wp;\r
734   char *filepart;\r
735 \r
736   hInst = hInstance;    /* Store instance handle in our global variable */\r
737 \r
738   if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {\r
739     *filepart = NULLCHAR;\r
740   } else {\r
741     GetCurrentDirectory(MSG_SIZ, installDir);\r
742   }\r
743   gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise\r
744   screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData\r
745   InitAppData(lpCmdLine);      /* Get run-time parameters */\r
746   if (appData.debugMode) {\r
747     debugFP = fopen(appData.nameOfDebugFile, "w");\r
748     setbuf(debugFP, NULL);\r
749   }\r
750 \r
751   InitBackEnd1();\r
752 \r
753 //  InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()\r
754 //  InitEngineUCI( installDir, &second );\r
755 \r
756   /* Create a main window for this application instance. */\r
757   hwnd = CreateWindow(szAppName, szTitle,\r
758                       (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),\r
759                       CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,\r
760                       NULL, NULL, hInstance, NULL);\r
761   hwndMain = hwnd;\r
762 \r
763   /* If window could not be created, return "failure" */\r
764   if (!hwnd) {\r
765     return (FALSE);\r
766   }\r
767 \r
768   /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */\r
769   if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {\r
770       first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
771 \r
772       if (first.programLogo == NULL && appData.debugMode) {\r
773           fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );\r
774       }\r
775   } else if(appData.autoLogo) {\r
776       if(appData.firstDirectory && appData.firstDirectory[0]) {\r
777         char buf[MSG_SIZ];\r
778         sprintf(buf, "%s/logo.bmp", appData.firstDirectory);\r
779         first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );   \r
780       }\r
781   }\r
782 \r
783   if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {\r
784       second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
785 \r
786       if (second.programLogo == NULL && appData.debugMode) {\r
787           fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );\r
788       }\r
789   } else if(appData.autoLogo) {\r
790       char buf[MSG_SIZ];\r
791       if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS\r
792         sprintf(buf, "logos\\%s.bmp", appData.icsHost);\r
793         second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
794       } else\r
795       if(appData.secondDirectory && appData.secondDirectory[0]) {\r
796         sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);\r
797         second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );  \r
798       }\r
799   }\r
800 \r
801   SetUserLogo();\r
802 \r
803   iconWhite = LoadIcon(hInstance, "icon_white");\r
804   iconBlack = LoadIcon(hInstance, "icon_black");\r
805   iconCurrent = iconWhite;\r
806   InitDrawingColors();\r
807   screenHeight = GetSystemMetrics(SM_CYSCREEN);\r
808   screenWidth = GetSystemMetrics(SM_CXSCREEN);\r
809   for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {\r
810     /* Compute window size for each board size, and use the largest\r
811        size that fits on this screen as the default. */\r
812     InitDrawingSizes((BoardSize)(ibs+1000), 0);\r
813     if (boardSize == (BoardSize)-1 &&\r
814         winH <= screenHeight\r
815            - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10\r
816         && winW <= screenWidth) {\r
817       boardSize = (BoardSize)ibs;\r
818     }\r
819   }\r
820 \r
821   InitDrawingSizes(boardSize, 0);\r
822   InitMenuChecks();\r
823   buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);\r
824 \r
825   /* [AS] Load textures if specified */\r
826   ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );\r
827   \r
828   if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {\r
829       liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
830       liteBackTextureMode = appData.liteBackTextureMode;\r
831 \r
832       if (liteBackTexture == NULL && appData.debugMode) {\r
833           fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );\r
834       }\r
835   }\r
836   \r
837   if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {\r
838       darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
839       darkBackTextureMode = appData.darkBackTextureMode;\r
840 \r
841       if (darkBackTexture == NULL && appData.debugMode) {\r
842           fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );\r
843       }\r
844   }\r
845 \r
846   mysrandom( (unsigned) time(NULL) );\r
847 \r
848   /* [AS] Restore layout */\r
849   if( wpMoveHistory.visible ) {\r
850       MoveHistoryPopUp();\r
851   }\r
852 \r
853   if( wpEvalGraph.visible ) {\r
854       EvalGraphPopUp();\r
855   }\r
856 \r
857   if( wpEngineOutput.visible ) {\r
858       EngineOutputPopUp();\r
859   }\r
860 \r
861   InitBackEnd2();\r
862 \r
863   /* Make the window visible; update its client area; and return "success" */\r
864   EnsureOnScreen(&boardX, &boardY, minX, minY);\r
865   wp.length = sizeof(WINDOWPLACEMENT);\r
866   wp.flags = 0;\r
867   wp.showCmd = nCmdShow;\r
868   wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;\r
869   wp.rcNormalPosition.left = boardX;\r
870   wp.rcNormalPosition.right = boardX + winWidth;\r
871   wp.rcNormalPosition.top = boardY;\r
872   wp.rcNormalPosition.bottom = boardY + winHeight;\r
873   SetWindowPlacement(hwndMain, &wp);\r
874 \r
875   if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
876                0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
877 \r
878   if (hwndConsole) {\r
879 #if AOT_CONSOLE\r
880     SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
881                  0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
882 #endif\r
883     ShowWindow(hwndConsole, nCmdShow);\r
884   }\r
885   if(!appData.noGUI)   UpdateWindow(hwnd);  else ShowWindow(hwnd, SW_MINIMIZE);\r
886   if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file\r
887 \r
888   return TRUE;\r
889 \r
890 }\r
891 \r
892 \r
893 typedef enum {\r
894   ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone, \r
895   ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,\r
896   ArgSettingsFilename,\r
897   ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window\r
898 } ArgType;\r
899 \r
900 typedef struct {\r
901   char *argName;\r
902   ArgType argType;\r
903   /***\r
904   union {\r
905     String *pString;       // ArgString\r
906     int *pInt;             // ArgInt\r
907     float *pFloat;         // ArgFloat\r
908     Boolean *pBoolean;     // ArgBoolean\r
909     COLORREF *pColor;      // ArgColor\r
910     ColorClass cc;         // ArgAttribs\r
911     String *pFilename;     // ArgFilename\r
912     BoardSize *pBoardSize; // ArgBoardSize\r
913     int whichFont;         // ArgFont\r
914     DCB *pDCB;             // ArgCommSettings\r
915     String *pFilename;     // ArgSettingsFilename\r
916   } argLoc;\r
917   ***/\r
918   LPVOID argLoc;\r
919   BOOL save;\r
920 } ArgDescriptor;\r
921 \r
922 int junk;\r
923 ArgDescriptor argDescriptors[] = {\r
924   /* positional arguments */\r
925   { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
926   { "", ArgNone, NULL },\r
927   /* keyword arguments */\r
928   JAWS_ARGS\r
929   { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },\r
930   { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },\r
931   { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },\r
932   { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },\r
933   { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },\r
934   { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },\r
935   { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },\r
936   { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },\r
937   { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },\r
938   { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },\r
939   { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },\r
940   { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },\r
941   { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },\r
942   { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },\r
943   { "initString", ArgString, (LPVOID) &appData.initString, FALSE },\r
944   { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },\r
945   { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },\r
946   { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,\r
947     FALSE },\r
948   { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,\r
949     FALSE },\r
950   { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,\r
951     FALSE },\r
952   { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },\r
953   { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,\r
954     FALSE },\r
955   { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },\r
956   { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
957   { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
958   { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
959   { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },\r
960   { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },\r
961   { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },\r
962   { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },\r
963   { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },\r
964   { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },\r
965   { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },\r
966   { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },\r
967   { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },\r
968   { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },\r
969   { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },\r
970   { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },\r
971   { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },\r
972   /*!!bitmapDirectory?*/\r
973   { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },\r
974   { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },\r
975   { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },\r
976   { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },\r
977   { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },\r
978   { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },\r
979   { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },\r
980   { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },\r
981   { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },\r
982   { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },\r
983   { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },\r
984   { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },\r
985   { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },\r
986   { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },\r
987   { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },\r
988   { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },\r
989   { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },\r
990   { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },\r
991   { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
992   { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
993   { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
994   { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },\r
995   { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },\r
996   { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },\r
997   { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },\r
998   { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },\r
999   { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },\r
1000   { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },\r
1001   { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },\r
1002   { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },\r
1003   { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },\r
1004   { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
1005   { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },\r
1006   { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },\r
1007   { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },\r
1008   { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },\r
1009   { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },\r
1010   { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },\r
1011   { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },\r
1012   { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },\r
1013   { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },\r
1014   { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },\r
1015   { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },\r
1016   { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },\r
1017   { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },\r
1018   { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },\r
1019   { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },\r
1020   { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },\r
1021   { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },\r
1022   { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },\r
1023   { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },\r
1024   { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },\r
1025   { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },\r
1026   { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },\r
1027   { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },\r
1028   { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },\r
1029   { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },\r
1030   { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },\r
1031   { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },\r
1032   { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },\r
1033   { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },\r
1034   { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },\r
1035   { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },\r
1036   { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },\r
1037   { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },\r
1038   { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },\r
1039   { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },\r
1040   { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },\r
1041   { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },\r
1042   { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },\r
1043   { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },\r
1044   { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },\r
1045   { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },\r
1046   { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },\r
1047   { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },\r
1048   { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },\r
1049   { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },\r
1050   { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },\r
1051   { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },\r
1052   { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },\r
1053   { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },\r
1054   { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },\r
1055   { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },\r
1056   { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },\r
1057   { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },\r
1058   { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },\r
1059   { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },\r
1060   { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },\r
1061   { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },\r
1062   { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },\r
1063   { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },\r
1064   { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },\r
1065   { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },\r
1066   { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, \r
1067     FALSE }, /* only so that old WinBoard.ini files from betas can be read */\r
1068   { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },\r
1069   { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },\r
1070   { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },\r
1071   { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },\r
1072   { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },\r
1073   { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },\r
1074   { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */\r
1075   { "boardSize", ArgBoardSize, (LPVOID) &boardSize,\r
1076     TRUE }, /* must come after all fonts */\r
1077   { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },\r
1078   { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,\r
1079     FALSE }, /* historical; kept only so old winboard.ini files will parse */\r
1080   { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },\r
1081   { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },\r
1082   { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },\r
1083   { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },\r
1084   { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },\r
1085   { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },\r
1086   { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },\r
1087   { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },\r
1088   { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },\r
1089   { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },\r
1090   { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },\r
1091   { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },\r
1092   { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },\r
1093   { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },\r
1094   { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },\r
1095   { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },\r
1096   { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },\r
1097   { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },\r
1098   { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },\r
1099   { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },\r
1100   { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },\r
1101   { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },\r
1102   { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },\r
1103   { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },\r
1104   { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },\r
1105   { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
1106   { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
1107   { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },\r
1108   { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },\r
1109   { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
1110   { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
1111   { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },\r
1112   { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },\r
1113   { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },\r
1114   { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },\r
1115   { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },\r
1116   { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },\r
1117   { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },\r
1118   { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },\r
1119   { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },\r
1120   { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },\r
1121   { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },\r
1122   { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },\r
1123   { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },\r
1124   { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },\r
1125   { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },\r
1126   { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },\r
1127   { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },\r
1128   { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },\r
1129   { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },\r
1130   { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },\r
1131   { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },\r
1132   { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },\r
1133   { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },\r
1134   { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },\r
1135   { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },\r
1136   { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },\r
1137   { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },\r
1138   { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },\r
1139   { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },\r
1140   { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },\r
1141   { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },\r
1142   { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},\r
1143   { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},\r
1144   { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},\r
1145   { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},\r
1146   { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},\r
1147   { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},\r
1148   { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},\r
1149   { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },\r
1150   { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },\r
1151   { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },\r
1152   { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },\r
1153   { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },\r
1154   { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },\r
1155   { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },\r
1156   { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },\r
1157   { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },\r
1158   { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },\r
1159   { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },\r
1160   { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },\r
1161   { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },\r
1162   { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },\r
1163   { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },\r
1164   { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },\r
1165   { "highlightLastMove", ArgBoolean,\r
1166     (LPVOID) &appData.highlightLastMove, TRUE },\r
1167   { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },\r
1168   { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },\r
1169   { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },\r
1170   { "highlightDragging", ArgBoolean,\r
1171     (LPVOID) &appData.highlightDragging, TRUE },\r
1172   { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },\r
1173   { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },\r
1174   { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },\r
1175   { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },\r
1176   { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },\r
1177   { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },\r
1178   { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },\r
1179   { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },\r
1180   { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },\r
1181   { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },\r
1182   { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },\r
1183   { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },\r
1184   { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },\r
1185   { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },\r
1186   { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },\r
1187   { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },\r
1188   { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },\r
1189   { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },\r
1190   { "soundShout", ArgFilename,\r
1191     (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },\r
1192   { "soundSShout", ArgFilename,\r
1193     (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },\r
1194   { "soundChannel1", ArgFilename,\r
1195     (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },\r
1196   { "soundChannel", ArgFilename,\r
1197     (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },\r
1198   { "soundKibitz", ArgFilename,\r
1199     (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },\r
1200   { "soundTell", ArgFilename,\r
1201     (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },\r
1202   { "soundChallenge", ArgFilename,\r
1203     (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },\r
1204   { "soundRequest", ArgFilename,\r
1205     (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },\r
1206   { "soundSeek", ArgFilename,\r
1207     (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },\r
1208   { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },\r
1209   { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },\r
1210   { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },\r
1211   { "soundIcsLoss", ArgFilename, \r
1212     (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },\r
1213   { "soundIcsDraw", ArgFilename, \r
1214     (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },\r
1215   { "soundIcsUnfinished", ArgFilename, \r
1216     (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},\r
1217   { "soundIcsAlarm", ArgFilename, \r
1218     (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },\r
1219   { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },\r
1220   { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },\r
1221   { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },\r
1222   { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },\r
1223   { "reuseChessPrograms", ArgBoolean,\r
1224     (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */\r
1225   { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },\r
1226   { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },\r
1227   { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },\r
1228   { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },\r
1229   { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },\r
1230   { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },\r
1231   { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },\r
1232   { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },\r
1233   { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },\r
1234   { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },\r
1235   { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },\r
1236   { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },\r
1237   { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },\r
1238   { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },\r
1239   { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,\r
1240     TRUE },\r
1241   { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,\r
1242     TRUE },\r
1243   { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },\r
1244   { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },\r
1245   { "variant", ArgString, (LPVOID) &appData.variant, FALSE },\r
1246   { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },\r
1247   { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },\r
1248   { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },\r
1249   { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },\r
1250   { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },\r
1251   { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },\r
1252   /* [AS] New features */\r
1253   { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },\r
1254   { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },\r
1255   { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },\r
1256   { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },\r
1257   { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },\r
1258   { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },\r
1259   { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },\r
1260   { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },\r
1261   { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },\r
1262   { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },\r
1263   { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },\r
1264   { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },\r
1265   { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },\r
1266   { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },\r
1267   { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },\r
1268   { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },\r
1269   { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },\r
1270   { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },\r
1271   { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },\r
1272   { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },\r
1273   { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },\r
1274   { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },\r
1275   { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },\r
1276   { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },\r
1277   { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },\r
1278   { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },\r
1279   { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },\r
1280   { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },\r
1281   { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },\r
1282   { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },\r
1283   { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },\r
1284   { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },\r
1285   { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },\r
1286   { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },\r
1287   { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },\r
1288   { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },\r
1289   { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },\r
1290   { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },\r
1291   { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
1292   { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
1293   { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
1294   { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
1295   { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
1296   { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
1297   { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },\r
1298   { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },\r
1299   { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },\r
1300   { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE }, \r
1301   { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },\r
1302   { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },\r
1303 \r
1304   /* [HGM] board-size, adjudication and misc. options */\r
1305   { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },\r
1306   { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },\r
1307   { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },\r
1308   { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },\r
1309   { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },\r
1310   { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },\r
1311   { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },\r
1312   { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },\r
1313   { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },\r
1314   { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },\r
1315   { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },\r
1316   { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },\r
1317   { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },\r
1318   { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },\r
1319   { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },\r
1320   { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },\r
1321   { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },\r
1322   { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },\r
1323   { "userName", ArgString, (LPVOID) &appData.userName, FALSE },\r
1324   { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },\r
1325   { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },\r
1326   { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },\r
1327   { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },\r
1328   { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },\r
1329   { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },\r
1330   { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },\r
1331   { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },\r
1332   { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },\r
1333   { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },\r
1334   { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },\r
1335   { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },\r
1336   { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },\r
1337   { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },\r
1338   { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE },\r
1339 \r
1340 #ifdef ZIPPY\r
1341   { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },\r
1342   { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },\r
1343   { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },\r
1344   { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },\r
1345   { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },\r
1346   { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },\r
1347   { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },\r
1348   { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },\r
1349   { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },\r
1350   { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },\r
1351   { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },\r
1352   { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },\r
1353   { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,\r
1354     FALSE },\r
1355   { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },\r
1356   { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },\r
1357   { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },\r
1358   { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },\r
1359   { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },\r
1360   { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },\r
1361   { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,\r
1362     FALSE },\r
1363   { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
1364   { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
1365   { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },\r
1366   { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },\r
1367   { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },\r
1368   { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },\r
1369   { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },\r
1370   { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },\r
1371   { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },\r
1372   { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },\r
1373   { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },\r
1374   { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },\r
1375   { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },\r
1376   { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },\r
1377   { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },\r
1378   { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },\r
1379   { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },\r
1380   /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */\r
1381   { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },\r
1382 #endif\r
1383   /* [HGM] options for broadcasting and time odds */\r
1384   { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },\r
1385   { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },\r
1386   { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },\r
1387   { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },\r
1388   { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },\r
1389   { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },\r
1390   { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },\r
1391   { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },\r
1392   { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },\r
1393   { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },\r
1394   { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },\r
1395   { "keepLineBreaksICS", ArgBoolean, (LPVOID) &appData.noJoin, TRUE },\r
1396   { "wrapContinuationSequence", ArgString, (LPVOID) &appData.wrapContSeq, FALSE },\r
1397   { "useInternalWrap", ArgTrue, (LPVOID) &appData.useInternalWrap, FALSE }, /* noJoin usurps this if set */\r
1398   \r
1399   // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others\r
1400   { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed\r
1401   { "minY", ArgZ, (LPVOID) &minY, FALSE },\r
1402   { "winWidth",  ArgInt, (LPVOID) &winWidth,  TRUE }, // [HGM] placement: dummies to remember right & bottom\r
1403   { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, //       for attaching auxiliary windows to them\r
1404   { "x", ArgInt, (LPVOID) &boardX, TRUE },\r
1405   { "y", ArgInt, (LPVOID) &boardY, TRUE },\r
1406   { "icsX", ArgX,   (LPVOID) &wpConsole.x, TRUE },\r
1407   { "icsY", ArgY,   (LPVOID) &wpConsole.y, TRUE },\r
1408   { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },\r
1409   { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },\r
1410   { "analysisX", ArgX,   (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists\r
1411   { "analysisY", ArgY,   (LPVOID) &analysisY, FALSE }, //       provided for compatibility with old ini files\r
1412   { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },\r
1413   { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },\r
1414   { "commentX", ArgX,   (LPVOID) &commentX, TRUE },\r
1415   { "commentY", ArgY,   (LPVOID) &commentY, TRUE },\r
1416   { "commentW", ArgInt, (LPVOID) &commentW, TRUE },\r
1417   { "commentH", ArgInt, (LPVOID) &commentH, TRUE },\r
1418   { "tagsX", ArgX,   (LPVOID) &editTagsX, TRUE },\r
1419   { "tagsY", ArgY,   (LPVOID) &editTagsY, TRUE },\r
1420   { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },\r
1421   { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },\r
1422   { "gameListX", ArgX,   (LPVOID) &wpGameList.x, TRUE },\r
1423   { "gameListY", ArgY,   (LPVOID) &wpGameList.y, TRUE },\r
1424   { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },\r
1425   { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },\r
1426   /* [AS] Layout stuff */\r
1427   { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },\r
1428   { "moveHistoryX", ArgX,   (LPVOID) &wpMoveHistory.x, TRUE },\r
1429   { "moveHistoryY", ArgY,   (LPVOID) &wpMoveHistory.y, TRUE },\r
1430   { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },\r
1431   { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },\r
1432 \r
1433   { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },\r
1434   { "evalGraphX", ArgX,   (LPVOID) &wpEvalGraph.x, TRUE },\r
1435   { "evalGraphY", ArgY,   (LPVOID) &wpEvalGraph.y, TRUE },\r
1436   { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },\r
1437   { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },\r
1438 \r
1439   { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },\r
1440   { "engineOutputX", ArgX,   (LPVOID) &wpEngineOutput.x, TRUE },\r
1441   { "engineOutputY", ArgY,   (LPVOID) &wpEngineOutput.y, TRUE },\r
1442   { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },\r
1443   { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },\r
1444 \r
1445   { NULL, ArgNone, NULL, FALSE }\r
1446 };\r
1447 \r
1448 \r
1449 /* Kludge for indirection files on command line */\r
1450 char* lastIndirectionFilename;\r
1451 ArgDescriptor argDescriptorIndirection =\r
1452 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };\r
1453 \r
1454 \r
1455 VOID\r
1456 ExitArgError(char *msg, char *badArg)\r
1457 {\r
1458   char buf[MSG_SIZ];\r
1459 \r
1460   sprintf(buf, "%s %s", msg, badArg);\r
1461   DisplayFatalError(buf, 0, 2);\r
1462   exit(2);\r
1463 }\r
1464 \r
1465 /* Command line font name parser.  NULL name means do nothing.\r
1466    Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"\r
1467    For backward compatibility, syntax without the colon is also\r
1468    accepted, but font names with digits in them won't work in that case.\r
1469 */\r
1470 VOID\r
1471 ParseFontName(char *name, MyFontParams *mfp)\r
1472 {\r
1473   char *p, *q;\r
1474   if (name == NULL) return;\r
1475   p = name;\r
1476   q = strchr(p, ':');\r
1477   if (q) {\r
1478     if (q - p >= sizeof(mfp->faceName))\r
1479       ExitArgError("Font name too long:", name);\r
1480     memcpy(mfp->faceName, p, q - p);\r
1481     mfp->faceName[q - p] = NULLCHAR;\r
1482     p = q + 1;\r
1483   } else {\r
1484     q = mfp->faceName;\r
1485     while (*p && !isdigit(*p)) {\r
1486       *q++ = *p++;\r
1487       if (q - mfp->faceName >= sizeof(mfp->faceName))\r
1488         ExitArgError("Font name too long:", name);\r
1489     }\r
1490     while (q > mfp->faceName && q[-1] == ' ') q--;\r
1491     *q = NULLCHAR;\r
1492   }\r
1493   if (!*p) ExitArgError("Font point size missing:", name);\r
1494   mfp->pointSize = (float) atof(p);\r
1495   mfp->bold = (strchr(p, 'b') != NULL);\r
1496   mfp->italic = (strchr(p, 'i') != NULL);\r
1497   mfp->underline = (strchr(p, 'u') != NULL);\r
1498   mfp->strikeout = (strchr(p, 's') != NULL);\r
1499   mfp->charset = DEFAULT_CHARSET;\r
1500   q = strchr(p, 'c');\r
1501   if (q)\r
1502     mfp->charset = (BYTE) atoi(q+1);\r
1503 }\r
1504 \r
1505 /* Color name parser.\r
1506    X version accepts X color names, but this one\r
1507    handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */\r
1508 COLORREF\r
1509 ParseColorName(char *name)\r
1510 {\r
1511   int red, green, blue, count;\r
1512   char buf[MSG_SIZ];\r
1513 \r
1514   count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);\r
1515   if (count != 3) {\r
1516     count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d", \r
1517       &red, &green, &blue);\r
1518   }\r
1519   if (count != 3) {\r
1520     sprintf(buf, "Can't parse color name %s", name);\r
1521     DisplayError(buf, 0);\r
1522     return RGB(0, 0, 0);\r
1523   }\r
1524   return PALETTERGB(red, green, blue);\r
1525 }\r
1526 \r
1527 \r
1528 void ParseAttribs(COLORREF *color, int *effects, char* argValue)\r
1529 {\r
1530   char *e = argValue;\r
1531   int eff = 0;\r
1532 \r
1533   while (*e) {\r
1534     if (*e == 'b')      eff |= CFE_BOLD;\r
1535     else if (*e == 'i') eff |= CFE_ITALIC;\r
1536     else if (*e == 'u') eff |= CFE_UNDERLINE;\r
1537     else if (*e == 's') eff |= CFE_STRIKEOUT;\r
1538     else if (*e == '#' || isdigit(*e)) break;\r
1539     e++;\r
1540   }\r
1541   *effects = eff;\r
1542   *color   = ParseColorName(e);\r
1543 }\r
1544 \r
1545 \r
1546 BoardSize\r
1547 ParseBoardSize(char *name)\r
1548 {\r
1549   BoardSize bs = SizeTiny;\r
1550   while (sizeInfo[bs].name != NULL) {\r
1551     if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;\r
1552     bs++;\r
1553   }\r
1554   ExitArgError("Unrecognized board size value", name);\r
1555   return bs; /* not reached */\r
1556 }\r
1557 \r
1558 \r
1559 char\r
1560 StringGet(void *getClosure)\r
1561 {\r
1562   char **p = (char **) getClosure;\r
1563   return *((*p)++);\r
1564 }\r
1565 \r
1566 char\r
1567 FileGet(void *getClosure)\r
1568 {\r
1569   int c;\r
1570   FILE* f = (FILE*) getClosure;\r
1571 \r
1572   c = getc(f);\r
1573   if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely\r
1574   if (c == EOF)\r
1575     return NULLCHAR;\r
1576   else\r
1577     return (char) c;\r
1578 }\r
1579 \r
1580 /* Parse settings file named "name". If file found, return the\r
1581    full name in fullname and return TRUE; else return FALSE */\r
1582 BOOLEAN\r
1583 ParseSettingsFile(char *name, char fullname[MSG_SIZ])\r
1584 {\r
1585   char *dummy;\r
1586   FILE *f;\r
1587   int ok; char buf[MSG_SIZ];\r
1588 \r
1589   ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);\r
1590   if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed\r
1591     sprintf(buf, "%s.ini", name);\r
1592     ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);\r
1593   }\r
1594   if (ok) {\r
1595     f = fopen(fullname, "r");\r
1596     if (f != NULL) {\r
1597       ParseArgs(FileGet, f);\r
1598       fclose(f);\r
1599       return TRUE;\r
1600     }\r
1601   }\r
1602   return FALSE;\r
1603 }\r
1604 \r
1605 VOID\r
1606 ParseArgs(GetFunc get, void *cl)\r
1607 {\r
1608   char argName[ARG_MAX];\r
1609   char argValue[ARG_MAX];\r
1610   ArgDescriptor *ad;\r
1611   char start;\r
1612   char *q;\r
1613   int i, octval;\r
1614   char ch;\r
1615   int posarg = 0;\r
1616 \r
1617   ch = get(cl);\r
1618   for (;;) {\r
1619     while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);\r
1620     if (ch == NULLCHAR) break;\r
1621     if (ch == ';') {\r
1622       /* Comment to end of line */\r
1623       ch = get(cl);\r
1624       while (ch != '\n' && ch != NULLCHAR) ch = get(cl);\r
1625       continue;\r
1626     } else if (ch == '/' || ch == '-') {\r
1627       /* Switch */\r
1628       q = argName;\r
1629       while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&\r
1630              ch != '\n' && ch != '\t') {\r
1631         *q++ = ch;\r
1632         ch = get(cl);\r
1633       }\r
1634       *q = NULLCHAR;\r
1635 \r
1636       for (ad = argDescriptors; ad->argName != NULL; ad++)\r
1637         if (strcmp(ad->argName, argName + 1) == 0) break;\r
1638 \r
1639       if (ad->argName == NULL)\r
1640         ExitArgError("Unrecognized argument", argName);\r
1641 \r
1642     } else if (ch == '@') {\r
1643       /* Indirection file */\r
1644       ad = &argDescriptorIndirection;\r
1645       ch = get(cl);\r
1646     } else {\r
1647       /* Positional argument */\r
1648       ad = &argDescriptors[posarg++];\r
1649       strcpy(argName, ad->argName);\r
1650     }\r
1651 \r
1652     if (ad->argType == ArgTrue) {\r
1653       *(Boolean *) ad->argLoc = TRUE;\r
1654       continue;\r
1655     }\r
1656     if (ad->argType == ArgFalse) {\r
1657       *(Boolean *) ad->argLoc = FALSE;\r
1658       continue;\r
1659     }\r
1660 \r
1661     while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);\r
1662     if (ch == NULLCHAR || ch == '\n') {\r
1663       ExitArgError("No value provided for argument", argName);\r
1664     }\r
1665     q = argValue;\r
1666     if (ch == '{') {\r
1667       // Quoting with { }.  No characters have to (or can) be escaped.\r
1668       // Thus the string cannot contain a '}' character.\r
1669       start = ch;\r
1670       ch = get(cl);\r
1671       while (start) {\r
1672         switch (ch) {\r
1673         case NULLCHAR:\r
1674           start = NULLCHAR;\r
1675           break;\r
1676           \r
1677         case '}':\r
1678           ch = get(cl);\r
1679           start = NULLCHAR;\r
1680           break;\r
1681 \r
1682         default:\r
1683           *q++ = ch;\r
1684           ch = get(cl);\r
1685           break;\r
1686         }\r
1687       }   \r
1688     } else if (ch == '\'' || ch == '"') {\r
1689       // Quoting with ' ' or " ", with \ as escape character.\r
1690       // Inconvenient for long strings that may contain Windows filenames.\r
1691       start = ch;\r
1692       ch = get(cl);\r
1693       while (start) {\r
1694         switch (ch) {\r
1695         case NULLCHAR:\r
1696           start = NULLCHAR;\r
1697           break;\r
1698 \r
1699         default:\r
1700         not_special:\r
1701           *q++ = ch;\r
1702           ch = get(cl);\r
1703           break;\r
1704 \r
1705         case '\'':\r
1706         case '\"':\r
1707           if (ch == start) {\r
1708             ch = get(cl);\r
1709             start = NULLCHAR;\r
1710             break;\r
1711           } else {\r
1712             goto not_special;\r
1713           }\r
1714 \r
1715         case '\\':\r
1716           if (ad->argType == ArgFilename\r
1717               || ad->argType == ArgSettingsFilename) {\r
1718               goto not_special;\r
1719           }\r
1720           ch = get(cl);\r
1721           switch (ch) {\r
1722           case NULLCHAR:\r
1723             ExitArgError("Incomplete \\ escape in value for", argName);\r
1724             break;\r
1725           case 'n':\r
1726             *q++ = '\n';\r
1727             ch = get(cl);\r
1728             break;\r
1729           case 'r':\r
1730             *q++ = '\r';\r
1731             ch = get(cl);\r
1732             break;\r
1733           case 't':\r
1734             *q++ = '\t';\r
1735             ch = get(cl);\r
1736             break;\r
1737           case 'b':\r
1738             *q++ = '\b';\r
1739             ch = get(cl);\r
1740             break;\r
1741           case 'f':\r
1742             *q++ = '\f';\r
1743             ch = get(cl);\r
1744             break;\r
1745           default:\r
1746             octval = 0;\r
1747             for (i = 0; i < 3; i++) {\r
1748               if (ch >= '0' && ch <= '7') {\r
1749                 octval = octval*8 + (ch - '0');\r
1750                 ch = get(cl);\r
1751               } else {\r
1752                 break;\r
1753               }\r
1754             }\r
1755             if (i > 0) {\r
1756               *q++ = (char) octval;\r
1757             } else {\r
1758               *q++ = ch;\r
1759               ch = get(cl);\r
1760             }\r
1761             break;\r
1762           }\r
1763           break;\r
1764         }\r
1765       }\r
1766     } else {\r
1767       while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {\r
1768         *q++ = ch;\r
1769         ch = get(cl);\r
1770       }\r
1771     }\r
1772     *q = NULLCHAR;\r
1773 \r
1774     switch (ad->argType) {\r
1775     case ArgInt:\r
1776       *(int *) ad->argLoc = atoi(argValue);\r
1777       break;\r
1778 \r
1779     case ArgX:\r
1780       *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute \r
1781       break;\r
1782 \r
1783     case ArgY:\r
1784       *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)\r
1785       break;\r
1786 \r
1787     case ArgZ:\r
1788       *(int *) ad->argLoc = atoi(argValue);\r
1789       EnsureOnScreen(&boardX, &boardY, minX, minY); \r
1790       break;\r
1791 \r
1792     case ArgFloat:\r
1793       *(float *) ad->argLoc = (float) atof(argValue);\r
1794       break;\r
1795 \r
1796     case ArgString:\r
1797     case ArgFilename:\r
1798       *(char **) ad->argLoc = strdup(argValue);\r
1799       break;\r
1800 \r
1801     case ArgSettingsFilename:\r
1802       {\r
1803         char fullname[MSG_SIZ];\r
1804         if (ParseSettingsFile(argValue, fullname)) {\r
1805           if (ad->argLoc != NULL) {\r
1806             *(char **) ad->argLoc = strdup(fullname);\r
1807           }\r
1808         } else {\r
1809           if (ad->argLoc != NULL) {\r
1810           } else {\r
1811             ExitArgError("Failed to open indirection file", argValue);\r
1812           }\r
1813         }\r
1814       }\r
1815       break;\r
1816 \r
1817     case ArgBoolean:\r
1818       switch (argValue[0]) {\r
1819       case 't':\r
1820       case 'T':\r
1821         *(Boolean *) ad->argLoc = TRUE;\r
1822         break;\r
1823       case 'f':\r
1824       case 'F':\r
1825         *(Boolean *) ad->argLoc = FALSE;\r
1826         break;\r
1827       default:\r
1828         ExitArgError("Unrecognized boolean argument value", argValue);\r
1829         break;\r
1830       }\r
1831       break;\r
1832 \r
1833     case ArgColor:\r
1834       *(COLORREF *)ad->argLoc = ParseColorName(argValue);\r
1835       break;\r
1836 \r
1837     case ArgAttribs: {\r
1838       ColorClass cc = (ColorClass)ad->argLoc;\r
1839       ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);\r
1840       }\r
1841       break;\r
1842       \r
1843     case ArgBoardSize:\r
1844       *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);\r
1845       break;\r
1846 \r
1847     case ArgFont:\r
1848       ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);\r
1849       break;\r
1850 \r
1851     case ArgCommSettings:\r
1852       ParseCommSettings(argValue, &dcb);\r
1853       break;\r
1854 \r
1855     case ArgNone:\r
1856       ExitArgError("Unrecognized argument", argValue);\r
1857       break;\r
1858     case ArgTrue:\r
1859     case ArgFalse: ;\r
1860     }\r
1861   }\r
1862 }\r
1863 \r
1864 VOID\r
1865 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)\r
1866 {\r
1867   HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);\r
1868   lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);\r
1869   DeleteDC(hdc);\r
1870   lf->lfWidth = 0;\r
1871   lf->lfEscapement = 0;\r
1872   lf->lfOrientation = 0;\r
1873   lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;\r
1874   lf->lfItalic = mfp->italic;\r
1875   lf->lfUnderline = mfp->underline;\r
1876   lf->lfStrikeOut = mfp->strikeout;\r
1877   lf->lfCharSet = mfp->charset;\r
1878   lf->lfOutPrecision = OUT_DEFAULT_PRECIS;\r
1879   lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
1880   lf->lfQuality = DEFAULT_QUALITY;\r
1881   lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;\r
1882   strcpy(lf->lfFaceName, mfp->faceName);\r
1883 }\r
1884 \r
1885 VOID\r
1886 CreateFontInMF(MyFont *mf)\r
1887 {\r
1888   LFfromMFP(&mf->lf, &mf->mfp);\r
1889   if (mf->hf) DeleteObject(mf->hf);\r
1890   mf->hf = CreateFontIndirect(&mf->lf);\r
1891 }\r
1892 \r
1893 VOID\r
1894 SetDefaultTextAttribs()\r
1895 {\r
1896   ColorClass cc;\r
1897   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1898     ParseAttribs(&textAttribs[cc].color, \r
1899                  &textAttribs[cc].effects, \r
1900                  defaultTextAttribs[cc]);\r
1901   }\r
1902 }\r
1903 \r
1904 VOID\r
1905 SetDefaultSounds()\r
1906 {\r
1907   ColorClass cc;\r
1908   SoundClass sc;\r
1909   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1910     textAttribs[cc].sound.name = strdup("");\r
1911     textAttribs[cc].sound.data = NULL;\r
1912   }\r
1913   for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
1914     sounds[sc].name = strdup("");\r
1915     sounds[sc].data = NULL;\r
1916   }\r
1917   sounds[(int)SoundBell].name = strdup(SOUND_BELL);\r
1918 }\r
1919 \r
1920 VOID\r
1921 LoadAllSounds()\r
1922 {\r
1923   ColorClass cc;\r
1924   SoundClass sc;\r
1925   for (cc = (ColorClass)0; cc < NColorClasses; cc++) {\r
1926     MyLoadSound(&textAttribs[cc].sound);\r
1927   }\r
1928   for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {\r
1929     MyLoadSound(&sounds[sc]);\r
1930   }\r
1931 }\r
1932 \r
1933 VOID\r
1934 InitAppData(LPSTR lpCmdLine)\r
1935 {\r
1936   int i, j;\r
1937   char buf[ARG_MAX], currDir[MSG_SIZ];\r
1938   char *dummy, *p;\r
1939 \r
1940   programName = szAppName;\r
1941 \r
1942   /* Initialize to defaults */\r
1943   lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);\r
1944   darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);\r
1945   whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);\r
1946   blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);\r
1947   highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);\r
1948   premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);\r
1949   consoleBackgroundColor = ParseColorName(COLOR_BKGD);\r
1950   SetDefaultTextAttribs();\r
1951   SetDefaultSounds();\r
1952   appData.movesPerSession = MOVES_PER_SESSION;\r
1953   appData.initString = INIT_STRING;\r
1954   appData.secondInitString = INIT_STRING;\r
1955   appData.firstComputerString = COMPUTER_STRING;\r
1956   appData.secondComputerString = COMPUTER_STRING;\r
1957   appData.firstChessProgram = FIRST_CHESS_PROGRAM;\r
1958   appData.secondChessProgram = SECOND_CHESS_PROGRAM;\r
1959   appData.firstPlaysBlack = FALSE;\r
1960   appData.noChessProgram = FALSE;\r
1961   chessProgram = FALSE;\r
1962   appData.firstHost = FIRST_HOST;\r
1963   appData.secondHost = SECOND_HOST;\r
1964   appData.firstDirectory = FIRST_DIRECTORY;\r
1965   appData.secondDirectory = SECOND_DIRECTORY;\r
1966   appData.bitmapDirectory = "";\r
1967   appData.remoteShell = REMOTE_SHELL;\r
1968   appData.remoteUser = "";\r
1969   appData.timeDelay = TIME_DELAY;\r
1970   appData.timeControl = TIME_CONTROL;\r
1971   appData.timeIncrement = TIME_INCREMENT;\r
1972   appData.icsActive = FALSE;\r
1973   appData.icsHost = "";\r
1974   appData.icsPort = ICS_PORT;\r
1975   appData.icsCommPort = ICS_COMM_PORT;\r
1976   appData.icsLogon = ICS_LOGON;\r
1977   appData.icsHelper = "";\r
1978   appData.useTelnet = FALSE;\r
1979   appData.telnetProgram = TELNET_PROGRAM;\r
1980   appData.gateway = "";\r
1981   appData.loadGameFile = "";\r
1982   appData.loadGameIndex = 0;\r
1983   appData.saveGameFile = "";\r
1984   appData.autoSaveGames = FALSE;\r
1985   appData.loadPositionFile = "";\r
1986   appData.loadPositionIndex = 1;\r
1987   appData.savePositionFile = "";\r
1988   appData.matchMode = FALSE;\r
1989   appData.matchGames = 0;\r
1990   appData.monoMode = FALSE;\r
1991   appData.debugMode = FALSE;\r
1992   appData.clockMode = TRUE;\r
1993   boardSize = (BoardSize) -1; /* determine by screen size */\r
1994   appData.Iconic = FALSE; /*unused*/\r
1995   appData.searchTime = "";\r
1996   appData.searchDepth = 0;\r
1997   appData.showCoords = FALSE;\r
1998   appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/\r
1999   appData.autoCallFlag = FALSE;\r
2000   appData.flipView = FALSE;\r
2001   appData.autoFlipView = TRUE;\r
2002   appData.cmailGameName = "";\r
2003   appData.alwaysPromoteToQueen = FALSE;\r
2004   appData.oldSaveStyle = FALSE;\r
2005   appData.quietPlay = FALSE;\r
2006   appData.showThinking = FALSE;\r
2007   appData.ponderNextMove = TRUE;\r
2008   appData.periodicUpdates = TRUE;\r
2009   appData.popupExitMessage = TRUE;\r
2010   appData.popupMoveErrors = FALSE;\r
2011   appData.autoObserve = FALSE;\r
2012   appData.autoComment = FALSE;\r
2013   appData.animate = TRUE;\r
2014   appData.animSpeed = 10;\r
2015   appData.animateDragging = TRUE;\r
2016   appData.highlightLastMove = TRUE;\r
2017   appData.getMoveList = TRUE;\r
2018   appData.testLegality = TRUE;\r
2019   appData.premove = TRUE;\r
2020   appData.premoveWhite = FALSE;\r
2021   appData.premoveWhiteText = "";\r
2022   appData.premoveBlack = FALSE;\r
2023   appData.premoveBlackText = "";\r
2024   appData.icsAlarm = TRUE;\r
2025   appData.icsAlarmTime = 5000;\r
2026   appData.autoRaiseBoard = TRUE;\r
2027   appData.localLineEditing = TRUE;\r
2028   appData.colorize = TRUE;\r
2029   appData.reuseFirst = TRUE;\r
2030   appData.reuseSecond = TRUE;\r
2031   appData.blindfold = FALSE;\r
2032   appData.icsEngineAnalyze = FALSE;\r
2033   memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +\r
2034   dcb.DCBlength = sizeof(DCB);\r
2035   dcb.BaudRate = 9600;\r
2036   dcb.fBinary = TRUE;\r
2037   dcb.fParity = FALSE;\r
2038   dcb.fOutxCtsFlow = FALSE;\r
2039   dcb.fOutxDsrFlow = FALSE;\r
2040   dcb.fDtrControl = DTR_CONTROL_ENABLE;\r
2041   dcb.fDsrSensitivity = FALSE;\r
2042   dcb.fTXContinueOnXoff = TRUE;\r
2043   dcb.fOutX = FALSE;\r
2044   dcb.fInX = FALSE;\r
2045   dcb.fNull = FALSE;\r
2046   dcb.fRtsControl = RTS_CONTROL_ENABLE;\r
2047   dcb.fAbortOnError = FALSE;\r
2048   dcb.ByteSize = 7;\r
2049   dcb.Parity = SPACEPARITY;\r
2050   dcb.StopBits = ONESTOPBIT;\r
2051   settingsFileName = SETTINGS_FILE;\r
2052   saveSettingsOnExit = TRUE;\r
2053   boardX = CW_USEDEFAULT;\r
2054   boardY = CW_USEDEFAULT;\r
2055   analysisX = CW_USEDEFAULT; \r
2056   analysisY = CW_USEDEFAULT; \r
2057   analysisW = CW_USEDEFAULT;\r
2058   analysisH = CW_USEDEFAULT;\r
2059   commentX = CW_USEDEFAULT; \r
2060   commentY = CW_USEDEFAULT; \r
2061   commentW = CW_USEDEFAULT;\r
2062   commentH = CW_USEDEFAULT;\r
2063   editTagsX = CW_USEDEFAULT; \r
2064   editTagsY = CW_USEDEFAULT; \r
2065   editTagsW = CW_USEDEFAULT;\r
2066   editTagsH = CW_USEDEFAULT;\r
2067   icsTextMenuString = ICS_TEXT_MENU_DEFAULT;\r
2068   icsNames = ICS_NAMES;\r
2069   firstChessProgramNames = FCP_NAMES;\r
2070   secondChessProgramNames = SCP_NAMES;\r
2071   appData.initialMode = "";\r
2072   appData.variant = "normal";\r
2073   appData.firstProtocolVersion = PROTOVER;\r
2074   appData.secondProtocolVersion = PROTOVER;\r
2075   appData.showButtonBar = TRUE;\r
2076 \r
2077    /* [AS] New properties (see comments in header file) */\r
2078   appData.firstScoreIsAbsolute = FALSE;\r
2079   appData.secondScoreIsAbsolute = FALSE;\r
2080   appData.saveExtendedInfoInPGN = FALSE;\r
2081   appData.hideThinkingFromHuman = FALSE;\r
2082   appData.liteBackTextureFile = "";\r
2083   appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
2084   appData.darkBackTextureFile = "";\r
2085   appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
2086   appData.renderPiecesWithFont = "";\r
2087   appData.fontToPieceTable = "";\r
2088   appData.fontBackColorWhite = 0;\r
2089   appData.fontForeColorWhite = 0;\r
2090   appData.fontBackColorBlack = 0;\r
2091   appData.fontForeColorBlack = 0;\r
2092   appData.fontPieceSize = 80;\r
2093   appData.overrideLineGap = 1;\r
2094   appData.adjudicateLossThreshold = 0;\r
2095   appData.delayBeforeQuit = 0;\r
2096   appData.delayAfterQuit = 0;\r
2097   appData.nameOfDebugFile = "winboard.debug";\r
2098   appData.pgnEventHeader = "Computer Chess Game";\r
2099   appData.defaultFrcPosition = -1;\r
2100   appData.gameListTags = GLT_DEFAULT_TAGS;\r
2101   appData.saveOutOfBookInfo = TRUE;\r
2102   appData.showEvalInMoveHistory = TRUE;\r
2103   appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );\r
2104   appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );\r
2105   appData.highlightMoveWithArrow = FALSE;\r
2106   appData.highlightArrowColor = ParseColorName( "#FFFF80" );\r
2107   appData.useStickyWindows = TRUE;\r
2108   appData.adjudicateDrawMoves = 0;\r
2109   appData.autoDisplayComment = TRUE;\r
2110   appData.autoDisplayTags = TRUE;\r
2111   appData.firstIsUCI = FALSE;\r
2112   appData.secondIsUCI = FALSE;\r
2113   appData.firstHasOwnBookUCI = TRUE;\r
2114   appData.secondHasOwnBookUCI = TRUE;\r
2115   appData.polyglotDir = "";\r
2116   appData.usePolyglotBook = FALSE;\r
2117   appData.polyglotBook = "";\r
2118   appData.defaultHashSize = 64;\r
2119   appData.defaultCacheSizeEGTB = 4;\r
2120   appData.defaultPathEGTB = "c:\\egtb";\r
2121   appData.firstOptions = "";\r
2122   appData.secondOptions = "";\r
2123 \r
2124   InitWindowPlacement( &wpGameList );\r
2125   InitWindowPlacement( &wpMoveHistory );\r
2126   InitWindowPlacement( &wpEvalGraph );\r
2127   InitWindowPlacement( &wpEngineOutput );\r
2128   InitWindowPlacement( &wpConsole );\r
2129 \r
2130   /* [HGM] User-selectable board size, adjudication control, miscellaneous */\r
2131   appData.NrFiles      = -1;\r
2132   appData.NrRanks      = -1;\r
2133   appData.holdingsSize = -1;\r
2134   appData.testClaims   = FALSE;\r
2135   appData.checkMates   = FALSE;\r
2136   appData.materialDraws= FALSE;\r
2137   appData.trivialDraws = FALSE;\r
2138   appData.ruleMoves    = 51;\r
2139   appData.drawRepeats  = 6;\r
2140   appData.matchPause   = 10000;\r
2141   appData.alphaRank    = FALSE;\r
2142   appData.allWhite     = FALSE;\r
2143   appData.upsideDown   = FALSE;\r
2144   appData.serverPause  = 15;\r
2145   appData.serverMovesName   = NULL;\r
2146   appData.suppressLoadMoves = FALSE;\r
2147   appData.firstTimeOdds  = 1;\r
2148   appData.secondTimeOdds = 1;\r
2149   appData.firstAccumulateTC  = 1; // combine previous and current sessions\r
2150   appData.secondAccumulateTC = 1;\r
2151   appData.firstNPS  = -1; // [HGM] nps: use wall-clock time\r
2152   appData.secondNPS = -1;\r
2153   appData.engineComments = 1;\r
2154   appData.smpCores = 1; // [HGM] SMP: max nr of cores\r
2155   appData.egtFormats = "";\r
2156 \r
2157 #ifdef ZIPPY\r
2158   appData.zippyTalk = ZIPPY_TALK;\r
2159   appData.zippyPlay = ZIPPY_PLAY;\r
2160   appData.zippyLines = ZIPPY_LINES;\r
2161   appData.zippyPinhead = ZIPPY_PINHEAD;\r
2162   appData.zippyPassword = ZIPPY_PASSWORD;\r
2163   appData.zippyPassword2 = ZIPPY_PASSWORD2;\r
2164   appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;\r
2165   appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;\r
2166   appData.zippyUseI = ZIPPY_USE_I;\r
2167   appData.zippyBughouse = ZIPPY_BUGHOUSE;\r
2168   appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;\r
2169   appData.zippyGameEnd = ZIPPY_GAME_END;\r
2170   appData.zippyGameStart = ZIPPY_GAME_START;\r
2171   appData.zippyAdjourn = ZIPPY_ADJOURN;\r
2172   appData.zippyAbort = ZIPPY_ABORT;\r
2173   appData.zippyVariants = ZIPPY_VARIANTS;\r
2174   appData.zippyMaxGames = ZIPPY_MAX_GAMES;\r
2175   appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;\r
2176 #endif\r
2177 \r
2178   /* Point font array elements to structures and\r
2179      parse default font names */\r
2180   for (i=0; i<NUM_FONTS; i++) {\r
2181     for (j=0; j<NUM_SIZES; j++) {\r
2182       font[j][i] = &fontRec[j][i];\r
2183       ParseFontName(font[j][i]->def, &font[j][i]->mfp);\r
2184     }\r
2185   }\r
2186   \r
2187   /* Parse default settings file if any */\r
2188   if (ParseSettingsFile(settingsFileName, buf)) {\r
2189     settingsFileName = strdup(buf);\r
2190   }\r
2191 \r
2192   /* Parse command line */\r
2193   ParseArgs(StringGet, &lpCmdLine);\r
2194 \r
2195   /* [HGM] make sure board size is acceptable */\r
2196   if(appData.NrFiles > BOARD_SIZE ||\r
2197      appData.NrRanks > BOARD_SIZE   )\r
2198       DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);\r
2199 \r
2200   /* [HGM] After parsing the options from the .ini file, and overruling them\r
2201    * with options from the command line, we now make an even higher priority\r
2202    * overrule by WB options attached to the engine command line. This so that\r
2203    * tournament managers can use WB options (such as /timeOdds) that follow\r
2204    * the engines.\r
2205    */\r
2206   if(appData.firstChessProgram != NULL) {\r
2207       char *p = StrStr(appData.firstChessProgram, "WBopt");\r
2208       static char *f = "first";\r
2209       char buf[MSG_SIZ], *q = buf;\r
2210       if(p != NULL) { // engine command line contains WinBoard options\r
2211           sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"\r
2212           ParseArgs(StringGet, &q);\r
2213           p[-1] = 0; // cut them offengine command line\r
2214       }\r
2215   }\r
2216   // now do same for second chess program\r
2217   if(appData.secondChessProgram != NULL) {\r
2218       char *p = StrStr(appData.secondChessProgram, "WBopt");\r
2219       static char *s = "second";\r
2220       char buf[MSG_SIZ], *q = buf;\r
2221       if(p != NULL) { // engine command line contains WinBoard options\r
2222           sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"\r
2223           ParseArgs(StringGet, &q);\r
2224           p[-1] = 0; // cut them offengine command line\r
2225       }\r
2226   }\r
2227 \r
2228 \r
2229   /* Propagate options that affect others */\r
2230   if (appData.matchMode || appData.matchGames) chessProgram = TRUE;\r
2231   if (appData.icsActive || appData.noChessProgram) {\r
2232      chessProgram = FALSE;  /* not local chess program mode */\r
2233   }\r
2234 \r
2235   /* Open startup dialog if needed */\r
2236   if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||\r
2237       (appData.icsActive && *appData.icsHost == NULLCHAR) ||\r
2238       (chessProgram && (*appData.firstChessProgram == NULLCHAR ||\r
2239                         *appData.secondChessProgram == NULLCHAR))) {\r
2240     FARPROC lpProc;\r
2241     \r
2242     lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);\r
2243     DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);\r
2244     FreeProcInstance(lpProc);\r
2245   }\r
2246 \r
2247   /* Make sure save files land in the right (?) directory */\r
2248   if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {\r
2249     appData.saveGameFile = strdup(buf);\r
2250   }\r
2251   if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {\r
2252     appData.savePositionFile = strdup(buf);\r
2253   }\r
2254 \r
2255   /* Finish initialization for fonts and sounds */\r
2256   for (i=0; i<NUM_FONTS; i++) {\r
2257     for (j=0; j<NUM_SIZES; j++) {\r
2258       CreateFontInMF(font[j][i]);\r
2259     }\r
2260   }\r
2261   /* xboard, and older WinBoards, controlled the move sound with the\r
2262      appData.ringBellAfterMoves option.  In the current WinBoard, we\r
2263      always turn the option on (so that the backend will call us),\r
2264      then let the user turn the sound off by setting it to silence if\r
2265      desired.  To accommodate old winboard.ini files saved by old\r
2266      versions of WinBoard, we also turn off the sound if the option\r
2267      was initially set to false. */\r
2268   if (!appData.ringBellAfterMoves) {\r
2269     sounds[(int)SoundMove].name = strdup("");\r
2270     appData.ringBellAfterMoves = TRUE;\r
2271   }\r
2272   GetCurrentDirectory(MSG_SIZ, currDir);\r
2273   SetCurrentDirectory(installDir);\r
2274   LoadAllSounds();\r
2275   SetCurrentDirectory(currDir);\r
2276 \r
2277   p = icsTextMenuString;\r
2278   if (p[0] == '@') {\r
2279     FILE* f = fopen(p + 1, "r");\r
2280     if (f == NULL) {\r
2281       DisplayFatalError(p + 1, errno, 2);\r
2282       return;\r
2283     }\r
2284     i = fread(buf, 1, sizeof(buf)-1, f);\r
2285     fclose(f);\r
2286     buf[i] = NULLCHAR;\r
2287     p = buf;\r
2288   }\r
2289   ParseIcsTextMenu(strdup(p));\r
2290 }\r
2291 \r
2292 \r
2293 VOID\r
2294 InitMenuChecks()\r
2295 {\r
2296   HMENU hmenu = GetMenu(hwndMain);\r
2297 \r
2298   (void) EnableMenuItem(hmenu, IDM_CommPort,\r
2299                         MF_BYCOMMAND|((appData.icsActive &&\r
2300                                        *appData.icsCommPort != NULLCHAR) ?\r
2301                                       MF_ENABLED : MF_GRAYED));\r
2302   (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,\r
2303                        MF_BYCOMMAND|(saveSettingsOnExit ?\r
2304                                      MF_CHECKED : MF_UNCHECKED));\r
2305 }\r
2306 \r
2307 \r
2308 VOID\r
2309 SaveSettings(char* name)\r
2310 {\r
2311   FILE *f;\r
2312   ArgDescriptor *ad;\r
2313   WINDOWPLACEMENT wp;\r
2314   char dir[MSG_SIZ];\r
2315 \r
2316   if (!hwndMain) return;\r
2317 \r
2318   GetCurrentDirectory(MSG_SIZ, dir);\r
2319   SetCurrentDirectory(installDir);\r
2320   f = fopen(name, "w");\r
2321   SetCurrentDirectory(dir);\r
2322   if (f == NULL) {\r
2323     DisplayError(name, errno);\r
2324     return;\r
2325   }\r
2326   fprintf(f, ";\n");\r
2327   fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);\r
2328   fprintf(f, ";\n");\r
2329   fprintf(f, "; You can edit the values of options that are already set in this file,\n");\r
2330   fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");\r
2331   fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");\r
2332   fprintf(f, ";\n");\r
2333 \r
2334   wp.length = sizeof(WINDOWPLACEMENT);\r
2335   GetWindowPlacement(hwndMain, &wp);\r
2336   boardX = wp.rcNormalPosition.left;\r
2337   boardY = wp.rcNormalPosition.top;\r
2338 \r
2339   if (hwndConsole) {\r
2340     GetWindowPlacement(hwndConsole, &wp);\r
2341     wpConsole.x = wp.rcNormalPosition.left;\r
2342     wpConsole.y = wp.rcNormalPosition.top;\r
2343     wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2344     wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2345   }\r
2346 \r
2347   if (analysisDialog) {\r
2348     GetWindowPlacement(analysisDialog, &wp);\r
2349     analysisX = wp.rcNormalPosition.left;\r
2350     analysisY = wp.rcNormalPosition.top;\r
2351     analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2352     analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2353   }\r
2354 \r
2355   if (commentDialog) {\r
2356     GetWindowPlacement(commentDialog, &wp);\r
2357     commentX = wp.rcNormalPosition.left;\r
2358     commentY = wp.rcNormalPosition.top;\r
2359     commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2360     commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2361   }\r
2362 \r
2363   if (editTagsDialog) {\r
2364     GetWindowPlacement(editTagsDialog, &wp);\r
2365     editTagsX = wp.rcNormalPosition.left;\r
2366     editTagsY = wp.rcNormalPosition.top;\r
2367     editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2368     editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2369   }\r
2370 \r
2371   if (gameListDialog) {\r
2372     GetWindowPlacement(gameListDialog, &wp);\r
2373     wpGameList.x = wp.rcNormalPosition.left;\r
2374     wpGameList.y = wp.rcNormalPosition.top;\r
2375     wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2376     wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2377   }\r
2378 \r
2379   /* [AS] Move history */\r
2380   wpMoveHistory.visible = MoveHistoryIsUp();\r
2381   \r
2382   if( moveHistoryDialog ) {\r
2383     GetWindowPlacement(moveHistoryDialog, &wp);\r
2384     wpMoveHistory.x = wp.rcNormalPosition.left;\r
2385     wpMoveHistory.y = wp.rcNormalPosition.top;\r
2386     wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2387     wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2388   }\r
2389 \r
2390   /* [AS] Eval graph */\r
2391   wpEvalGraph.visible = EvalGraphIsUp();\r
2392 \r
2393   if( evalGraphDialog ) {\r
2394     GetWindowPlacement(evalGraphDialog, &wp);\r
2395     wpEvalGraph.x = wp.rcNormalPosition.left;\r
2396     wpEvalGraph.y = wp.rcNormalPosition.top;\r
2397     wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2398     wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2399   }\r
2400 \r
2401   /* [AS] Engine output */\r
2402   wpEngineOutput.visible = EngineOutputIsUp();\r
2403 \r
2404   if( engineOutputDialog ) {\r
2405     GetWindowPlacement(engineOutputDialog, &wp);\r
2406     wpEngineOutput.x = wp.rcNormalPosition.left;\r
2407     wpEngineOutput.y = wp.rcNormalPosition.top;\r
2408     wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
2409     wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
2410   }\r
2411 \r
2412   for (ad = argDescriptors; ad->argName != NULL; ad++) {\r
2413     if (!ad->save) continue;\r
2414     switch (ad->argType) {\r
2415     case ArgString:\r
2416       {\r
2417         char *p = *(char **)ad->argLoc;\r
2418         if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {\r
2419           /* Quote multiline values or \-containing values\r
2420              with { } if possible */\r
2421           fprintf(f, "/%s={%s}\n", ad->argName, p);\r
2422         } else {\r
2423           /* Else quote with " " */\r
2424           fprintf(f, "/%s=\"", ad->argName);\r
2425           while (*p) {\r
2426             if (*p == '\n') fprintf(f, "\n");\r
2427             else if (*p == '\r') fprintf(f, "\\r");\r
2428             else if (*p == '\t') fprintf(f, "\\t");\r
2429             else if (*p == '\b') fprintf(f, "\\b");\r
2430             else if (*p == '\f') fprintf(f, "\\f");\r
2431             else if (*p < ' ') fprintf(f, "\\%03o", *p);\r
2432             else if (*p == '\"') fprintf(f, "\\\"");\r
2433             else if (*p == '\\') fprintf(f, "\\\\");\r
2434             else putc(*p, f);\r
2435             p++;\r
2436           }\r
2437           fprintf(f, "\"\n");\r
2438         }\r
2439       }\r
2440       break;\r
2441     case ArgInt:\r
2442     case ArgZ:\r
2443       fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);\r
2444       break;\r
2445     case ArgX:\r
2446       fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value\r
2447       break;\r
2448     case ArgY:\r
2449       fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);\r
2450       break;\r
2451     case ArgFloat:\r
2452       fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);\r
2453       break;\r
2454     case ArgBoolean:\r
2455       fprintf(f, "/%s=%s\n", ad->argName, \r
2456         (*(Boolean *)ad->argLoc) ? "true" : "false");\r
2457       break;\r
2458     case ArgTrue:\r
2459       if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
2460       break;\r
2461     case ArgFalse:\r
2462       if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);\r
2463       break;\r
2464     case ArgColor:\r
2465       {\r
2466         COLORREF color = *(COLORREF *)ad->argLoc;\r
2467         fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName, \r
2468           color&0xff, (color>>8)&0xff, (color>>16)&0xff);\r
2469       }\r
2470       break;\r
2471     case ArgAttribs:\r
2472       {\r
2473         MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];\r
2474         fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,\r
2475           (ta->effects & CFE_BOLD) ? "b" : "",\r
2476           (ta->effects & CFE_ITALIC) ? "i" : "",\r
2477           (ta->effects & CFE_UNDERLINE) ? "u" : "",\r
2478           (ta->effects & CFE_STRIKEOUT) ? "s" : "",\r
2479           (ta->effects) ? " " : "",\r
2480           ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);\r
2481       }\r
2482       break;\r
2483     case ArgFilename:\r
2484       if (strchr(*(char **)ad->argLoc, '\"')) {\r
2485         fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);\r
2486       } else {\r
2487         fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);\r
2488       }\r
2489       break;\r
2490     case ArgBoardSize:\r
2491       fprintf(f, "/%s=%s\n", ad->argName,\r
2492               sizeInfo[*(BoardSize *)ad->argLoc].name);\r
2493       break;\r
2494     case ArgFont:\r
2495       {\r
2496         int bs;\r
2497         for (bs=0; bs<NUM_SIZES; bs++) {\r
2498           MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;\r
2499           fprintf(f, "/size=%s ", sizeInfo[bs].name);\r
2500           fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",\r
2501             ad->argName, mfp->faceName, mfp->pointSize,\r
2502             mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",\r
2503             mfp->bold ? "b" : "",\r
2504             mfp->italic ? "i" : "",\r
2505             mfp->underline ? "u" : "",\r
2506             mfp->strikeout ? "s" : "",\r
2507             (int)mfp->charset);\r
2508         }\r
2509       }\r
2510       break;\r
2511     case ArgCommSettings:\r
2512       PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);\r
2513     case ArgNone:\r
2514     case ArgSettingsFilename: ;\r
2515     }\r
2516   }\r
2517   fclose(f);\r
2518 }\r
2519 \r
2520 \r
2521 \r
2522 /*---------------------------------------------------------------------------*\\r
2523  *\r
2524  * GDI board drawing routines\r
2525  *\r
2526 \*---------------------------------------------------------------------------*/\r
2527 \r
2528 /* [AS] Draw square using background texture */\r
2529 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )\r
2530 {\r
2531     XFORM   x;\r
2532 \r
2533     if( mode == 0 ) {\r
2534         return; /* Should never happen! */\r
2535     }\r
2536 \r
2537     SetGraphicsMode( dst, GM_ADVANCED );\r
2538 \r
2539     switch( mode ) {\r
2540     case 1:\r
2541         /* Identity */\r
2542         break;\r
2543     case 2:\r
2544         /* X reflection */\r
2545         x.eM11 = -1.0;\r
2546         x.eM12 = 0;\r
2547         x.eM21 = 0;\r
2548         x.eM22 = 1.0;\r
2549         x.eDx = (FLOAT) dw + dx - 1;\r
2550         x.eDy = 0;\r
2551         dx = 0;\r
2552         SetWorldTransform( dst, &x );\r
2553         break;\r
2554     case 3:\r
2555         /* Y reflection */\r
2556         x.eM11 = 1.0;\r
2557         x.eM12 = 0;\r
2558         x.eM21 = 0;\r
2559         x.eM22 = -1.0;\r
2560         x.eDx = 0;\r
2561         x.eDy = (FLOAT) dh + dy - 1;\r
2562         dy = 0;\r
2563         SetWorldTransform( dst, &x );\r
2564         break;\r
2565     case 4:\r
2566         /* X/Y flip */\r
2567         x.eM11 = 0;\r
2568         x.eM12 = 1.0;\r
2569         x.eM21 = 1.0;\r
2570         x.eM22 = 0;\r
2571         x.eDx = (FLOAT) dx;\r
2572         x.eDy = (FLOAT) dy;\r
2573         dx = 0;\r
2574         dy = 0;\r
2575         SetWorldTransform( dst, &x );\r
2576         break;\r
2577     }\r
2578 \r
2579     BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );\r
2580 \r
2581     x.eM11 = 1.0;\r
2582     x.eM12 = 0;\r
2583     x.eM21 = 0;\r
2584     x.eM22 = 1.0;\r
2585     x.eDx = 0;\r
2586     x.eDy = 0;\r
2587     SetWorldTransform( dst, &x );\r
2588 \r
2589     ModifyWorldTransform( dst, 0, MWT_IDENTITY );\r
2590 }\r
2591 \r
2592 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */\r
2593 enum {\r
2594     PM_WP = (int) WhitePawn, \r
2595     PM_WN = (int) WhiteKnight, \r
2596     PM_WB = (int) WhiteBishop, \r
2597     PM_WR = (int) WhiteRook, \r
2598     PM_WQ = (int) WhiteQueen, \r
2599     PM_WF = (int) WhiteFerz, \r
2600     PM_WW = (int) WhiteWazir, \r
2601     PM_WE = (int) WhiteAlfil, \r
2602     PM_WM = (int) WhiteMan, \r
2603     PM_WO = (int) WhiteCannon, \r
2604     PM_WU = (int) WhiteUnicorn, \r
2605     PM_WH = (int) WhiteNightrider, \r
2606     PM_WA = (int) WhiteAngel, \r
2607     PM_WC = (int) WhiteMarshall, \r
2608     PM_WAB = (int) WhiteCardinal, \r
2609     PM_WD = (int) WhiteDragon, \r
2610     PM_WL = (int) WhiteLance, \r
2611     PM_WS = (int) WhiteCobra, \r
2612     PM_WV = (int) WhiteFalcon, \r
2613     PM_WSG = (int) WhiteSilver, \r
2614     PM_WG = (int) WhiteGrasshopper, \r
2615     PM_WK = (int) WhiteKing,\r
2616     PM_BP = (int) BlackPawn, \r
2617     PM_BN = (int) BlackKnight, \r
2618     PM_BB = (int) BlackBishop, \r
2619     PM_BR = (int) BlackRook, \r
2620     PM_BQ = (int) BlackQueen, \r
2621     PM_BF = (int) BlackFerz, \r
2622     PM_BW = (int) BlackWazir, \r
2623     PM_BE = (int) BlackAlfil, \r
2624     PM_BM = (int) BlackMan,\r
2625     PM_BO = (int) BlackCannon, \r
2626     PM_BU = (int) BlackUnicorn, \r
2627     PM_BH = (int) BlackNightrider, \r
2628     PM_BA = (int) BlackAngel, \r
2629     PM_BC = (int) BlackMarshall, \r
2630     PM_BG = (int) BlackGrasshopper, \r
2631     PM_BAB = (int) BlackCardinal,\r
2632     PM_BD = (int) BlackDragon,\r
2633     PM_BL = (int) BlackLance,\r
2634     PM_BS = (int) BlackCobra,\r
2635     PM_BV = (int) BlackFalcon,\r
2636     PM_BSG = (int) BlackSilver,\r
2637     PM_BK = (int) BlackKing\r
2638 };\r
2639 \r
2640 static HFONT hPieceFont = NULL;\r
2641 static HBITMAP hPieceMask[(int) EmptySquare];\r
2642 static HBITMAP hPieceFace[(int) EmptySquare];\r
2643 static int fontBitmapSquareSize = 0;\r
2644 static char pieceToFontChar[(int) EmptySquare] =\r
2645                               { 'p', 'n', 'b', 'r', 'q', \r
2646                       'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',\r
2647                       'k', 'o', 'm', 'v', 't', 'w', \r
2648                       'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',\r
2649                                                               'l' };\r
2650 \r
2651 extern BOOL SetCharTable( char *table, const char * map );\r
2652 /* [HGM] moved to backend.c */\r
2653 \r
2654 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )\r
2655 {\r
2656     HBRUSH hbrush;\r
2657     BYTE r1 = GetRValue( color );\r
2658     BYTE g1 = GetGValue( color );\r
2659     BYTE b1 = GetBValue( color );\r
2660     BYTE r2 = r1 / 2;\r
2661     BYTE g2 = g1 / 2;\r
2662     BYTE b2 = b1 / 2;\r
2663     RECT rc;\r
2664 \r
2665     /* Create a uniform background first */\r
2666     hbrush = CreateSolidBrush( color );\r
2667     SetRect( &rc, 0, 0, squareSize, squareSize );\r
2668     FillRect( hdc, &rc, hbrush );\r
2669     DeleteObject( hbrush );\r
2670     \r
2671     if( mode == 1 ) {\r
2672         /* Vertical gradient, good for pawn, knight and rook, less for queen and king */\r
2673         int steps = squareSize / 2;\r
2674         int i;\r
2675 \r
2676         for( i=0; i<steps; i++ ) {\r
2677             BYTE r = r1 - (r1-r2) * i / steps;\r
2678             BYTE g = g1 - (g1-g2) * i / steps;\r
2679             BYTE b = b1 - (b1-b2) * i / steps;\r
2680 \r
2681             hbrush = CreateSolidBrush( RGB(r,g,b) );\r
2682             SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );\r
2683             FillRect( hdc, &rc, hbrush );\r
2684             DeleteObject(hbrush);\r
2685         }\r
2686     }\r
2687     else if( mode == 2 ) {\r
2688         /* Diagonal gradient, good more or less for every piece */\r
2689         POINT triangle[3];\r
2690         HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );\r
2691         HBRUSH hbrush_old;\r
2692         int steps = squareSize;\r
2693         int i;\r
2694 \r
2695         triangle[0].x = squareSize - steps;\r
2696         triangle[0].y = squareSize;\r
2697         triangle[1].x = squareSize;\r
2698         triangle[1].y = squareSize;\r
2699         triangle[2].x = squareSize;\r
2700         triangle[2].y = squareSize - steps;\r
2701 \r
2702         for( i=0; i<steps; i++ ) {\r
2703             BYTE r = r1 - (r1-r2) * i / steps;\r
2704             BYTE g = g1 - (g1-g2) * i / steps;\r
2705             BYTE b = b1 - (b1-b2) * i / steps;\r
2706 \r
2707             hbrush = CreateSolidBrush( RGB(r,g,b) );\r
2708             hbrush_old = SelectObject( hdc, hbrush );\r
2709             Polygon( hdc, triangle, 3 );\r
2710             SelectObject( hdc, hbrush_old );\r
2711             DeleteObject(hbrush);\r
2712             triangle[0].x++;\r
2713             triangle[2].y++;\r
2714         }\r
2715 \r
2716         SelectObject( hdc, hpen );\r
2717     }\r
2718 }\r
2719 \r
2720 /*\r
2721     [AS] The method I use to create the bitmaps it a bit tricky, but it\r
2722     seems to work ok. The main problem here is to find the "inside" of a chess\r
2723     piece: follow the steps as explained below.\r
2724 */\r
2725 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )\r
2726 {\r
2727     HBITMAP hbm;\r
2728     HBITMAP hbm_old;\r
2729     COLORREF chroma = RGB(0xFF,0x00,0xFF);\r
2730     RECT rc;\r
2731     SIZE sz;\r
2732     POINT pt;\r
2733     int backColor = whitePieceColor; \r
2734     int foreColor = blackPieceColor;\r
2735     \r
2736     if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {\r
2737         backColor = appData.fontBackColorWhite;\r
2738         foreColor = appData.fontForeColorWhite;\r
2739     }\r
2740     else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {\r
2741         backColor = appData.fontBackColorBlack;\r
2742         foreColor = appData.fontForeColorBlack;\r
2743     }\r
2744 \r
2745     /* Mask */\r
2746     hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2747 \r
2748     hbm_old = SelectObject( hdc, hbm );\r
2749 \r
2750     rc.left = 0;\r
2751     rc.top = 0;\r
2752     rc.right = squareSize;\r
2753     rc.bottom = squareSize;\r
2754 \r
2755     /* Step 1: background is now black */\r
2756     FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );\r
2757 \r
2758     GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );\r
2759 \r
2760     pt.x = (squareSize - sz.cx) / 2;\r
2761     pt.y = (squareSize - sz.cy) / 2;\r
2762 \r
2763     SetBkMode( hdc, TRANSPARENT );\r
2764     SetTextColor( hdc, chroma );\r
2765     /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */\r
2766     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
2767 \r
2768     SelectObject( hdc, GetStockObject(WHITE_BRUSH) );\r
2769     /* Step 3: the area outside the piece is filled with white */\r
2770 //    FloodFill( hdc, 0, 0, chroma );\r
2771     ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );\r
2772     ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big\r
2773     ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );\r
2774     ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );\r
2775     SelectObject( hdc, GetStockObject(BLACK_BRUSH) );\r
2776     /* \r
2777         Step 4: this is the tricky part, the area inside the piece is filled with black,\r
2778         but if the start point is not inside the piece we're lost!\r
2779         There should be a better way to do this... if we could create a region or path\r
2780         from the fill operation we would be fine for example.\r
2781     */\r
2782 //    FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );\r
2783     ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );\r
2784 \r
2785     {   /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */\r
2786         HDC dc2 = CreateCompatibleDC( hdc_window );\r
2787         HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2788 \r
2789         SelectObject( dc2, bm2 );\r
2790         BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy\r
2791         BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2792         BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2793         BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2794         BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
2795 \r
2796         DeleteDC( dc2 );\r
2797         DeleteObject( bm2 );\r
2798     }\r
2799 \r
2800     SetTextColor( hdc, 0 );\r
2801     /* \r
2802         Step 5: some fonts have "disconnected" areas that are skipped by the fill:\r
2803         draw the piece again in black for safety.\r
2804     */\r
2805     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
2806 \r
2807     SelectObject( hdc, hbm_old );\r
2808 \r
2809     if( hPieceMask[index] != NULL ) {\r
2810         DeleteObject( hPieceMask[index] );\r
2811     }\r
2812 \r
2813     hPieceMask[index] = hbm;\r
2814 \r
2815     /* Face */\r
2816     hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2817 \r
2818     SelectObject( hdc, hbm );\r
2819 \r
2820     {\r
2821         HDC dc1 = CreateCompatibleDC( hdc_window );\r
2822         HDC dc2 = CreateCompatibleDC( hdc_window );\r
2823         HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
2824 \r
2825         SelectObject( dc1, hPieceMask[index] );\r
2826         SelectObject( dc2, bm2 );\r
2827         FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );\r
2828         BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );\r
2829         \r
2830         /* \r
2831             Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves\r
2832             the piece background and deletes (makes transparent) the rest.\r
2833             Thanks to that mask, we are free to paint the background with the greates\r
2834             freedom, as we'll be able to mask off the unwanted parts when finished.\r
2835             We use this, to make gradients and give the pieces a "roundish" look.\r
2836         */\r
2837         SetPieceBackground( hdc, backColor, 2 );\r
2838         BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );\r
2839 \r
2840         DeleteDC( dc2 );\r
2841         DeleteDC( dc1 );\r
2842         DeleteObject( bm2 );\r
2843     }\r
2844 \r
2845     SetTextColor( hdc, foreColor );\r
2846     TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
2847 \r
2848     SelectObject( hdc, hbm_old );\r
2849 \r
2850     if( hPieceFace[index] != NULL ) {\r
2851         DeleteObject( hPieceFace[index] );\r
2852     }\r
2853 \r
2854     hPieceFace[index] = hbm;\r
2855 }\r
2856 \r
2857 static int TranslatePieceToFontPiece( int piece )\r
2858 {\r
2859     switch( piece ) {\r
2860     case BlackPawn:\r
2861         return PM_BP;\r
2862     case BlackKnight:\r
2863         return PM_BN;\r
2864     case BlackBishop:\r
2865         return PM_BB;\r
2866     case BlackRook:\r
2867         return PM_BR;\r
2868     case BlackQueen:\r
2869         return PM_BQ;\r
2870     case BlackKing:\r
2871         return PM_BK;\r
2872     case WhitePawn:\r
2873         return PM_WP;\r
2874     case WhiteKnight:\r
2875         return PM_WN;\r
2876     case WhiteBishop:\r
2877         return PM_WB;\r
2878     case WhiteRook:\r
2879         return PM_WR;\r
2880     case WhiteQueen:\r
2881         return PM_WQ;\r
2882     case WhiteKing:\r
2883         return PM_WK;\r
2884 \r
2885     case BlackAngel:\r
2886         return PM_BA;\r
2887     case BlackMarshall:\r
2888         return PM_BC;\r
2889     case BlackFerz:\r
2890         return PM_BF;\r
2891     case BlackNightrider:\r
2892         return PM_BH;\r
2893     case BlackAlfil:\r
2894         return PM_BE;\r
2895     case BlackWazir:\r
2896         return PM_BW;\r
2897     case BlackUnicorn:\r
2898         return PM_BU;\r
2899     case BlackCannon:\r
2900         return PM_BO;\r
2901     case BlackGrasshopper:\r
2902         return PM_BG;\r
2903     case BlackMan:\r
2904         return PM_BM;\r
2905     case BlackSilver:\r
2906         return PM_BSG;\r
2907     case BlackLance:\r
2908         return PM_BL;\r
2909     case BlackFalcon:\r
2910         return PM_BV;\r
2911     case BlackCobra:\r
2912         return PM_BS;\r
2913     case BlackCardinal:\r
2914         return PM_BAB;\r
2915     case BlackDragon:\r
2916         return PM_BD;\r
2917 \r
2918     case WhiteAngel:\r
2919         return PM_WA;\r
2920     case WhiteMarshall:\r
2921         return PM_WC;\r
2922     case WhiteFerz:\r
2923         return PM_WF;\r
2924     case WhiteNightrider:\r
2925         return PM_WH;\r
2926     case WhiteAlfil:\r
2927         return PM_WE;\r
2928     case WhiteWazir:\r
2929         return PM_WW;\r
2930     case WhiteUnicorn:\r
2931         return PM_WU;\r
2932     case WhiteCannon:\r
2933         return PM_WO;\r
2934     case WhiteGrasshopper:\r
2935         return PM_WG;\r
2936     case WhiteMan:\r
2937         return PM_WM;\r
2938     case WhiteSilver:\r
2939         return PM_WSG;\r
2940     case WhiteLance:\r
2941         return PM_WL;\r
2942     case WhiteFalcon:\r
2943         return PM_WV;\r
2944     case WhiteCobra:\r
2945         return PM_WS;\r
2946     case WhiteCardinal:\r
2947         return PM_WAB;\r
2948     case WhiteDragon:\r
2949         return PM_WD;\r
2950     }\r
2951 \r
2952     return 0;\r
2953 }\r
2954 \r
2955 void CreatePiecesFromFont()\r
2956 {\r
2957     LOGFONT lf;\r
2958     HDC hdc_window = NULL;\r
2959     HDC hdc = NULL;\r
2960     HFONT hfont_old;\r
2961     int fontHeight;\r
2962     int i;\r
2963 \r
2964     if( fontBitmapSquareSize < 0 ) {\r
2965         /* Something went seriously wrong in the past: do not try to recreate fonts! */\r
2966         return;\r
2967     }\r
2968 \r
2969     if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {\r
2970         fontBitmapSquareSize = -1;\r
2971         return;\r
2972     }\r
2973 \r
2974     if( fontBitmapSquareSize != squareSize ) {\r
2975         hdc_window = GetDC( hwndMain );\r
2976         hdc = CreateCompatibleDC( hdc_window );\r
2977 \r
2978         if( hPieceFont != NULL ) {\r
2979             DeleteObject( hPieceFont );\r
2980         }\r
2981         else {\r
2982             for( i=0; i<=(int)BlackKing; i++ ) {\r
2983                 hPieceMask[i] = NULL;\r
2984                 hPieceFace[i] = NULL;\r
2985             }\r
2986         }\r
2987 \r
2988         fontHeight = 75;\r
2989 \r
2990         if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {\r
2991             fontHeight = appData.fontPieceSize;\r
2992         }\r
2993 \r
2994         fontHeight = (fontHeight * squareSize) / 100;\r
2995 \r
2996         lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );\r
2997         lf.lfWidth = 0;\r
2998         lf.lfEscapement = 0;\r
2999         lf.lfOrientation = 0;\r
3000         lf.lfWeight = FW_NORMAL;\r
3001         lf.lfItalic = 0;\r
3002         lf.lfUnderline = 0;\r
3003         lf.lfStrikeOut = 0;\r
3004         lf.lfCharSet = DEFAULT_CHARSET;\r
3005         lf.lfOutPrecision = OUT_DEFAULT_PRECIS;\r
3006         lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
3007         lf.lfQuality = PROOF_QUALITY;\r
3008         lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;\r
3009         strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );\r
3010         lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';\r
3011 \r
3012         hPieceFont = CreateFontIndirect( &lf );\r
3013 \r
3014         if( hPieceFont == NULL ) {\r
3015             fontBitmapSquareSize = -2;\r
3016         }\r
3017         else {\r
3018             /* Setup font-to-piece character table */\r
3019             if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {\r
3020                 /* No (or wrong) global settings, try to detect the font */\r
3021                 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {\r
3022                     /* Alpha */\r
3023                     SetCharTable(pieceToFontChar, "phbrqkojntwl");\r
3024                 }\r
3025                 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {\r
3026                     /* DiagramTT* family */\r
3027                     SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");\r
3028                 }\r
3029                 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {\r
3030                     /* Fairy symbols */\r
3031                      SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");\r
3032                 }\r
3033                 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {\r
3034                     /* Good Companion (Some characters get warped as literal :-( */\r
3035                     char s[] = "1cmWG0ñueOS¯®oYI23wgQU";\r
3036                     s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;\r
3037                     SetCharTable(pieceToFontChar, s);\r
3038                 }\r
3039                 else {\r
3040                     /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */\r
3041                     SetCharTable(pieceToFontChar, "pnbrqkomvtwl");\r
3042                 }\r
3043             }\r
3044 \r
3045             /* Create bitmaps */\r
3046             hfont_old = SelectObject( hdc, hPieceFont );\r
3047             for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */\r
3048                 if(PieceToChar((ChessSquare)i) != '.')     /* skip unused pieces         */\r
3049                     CreatePieceMaskFromFont( hdc_window, hdc, i );\r
3050 \r
3051             SelectObject( hdc, hfont_old );\r
3052 \r
3053             fontBitmapSquareSize = squareSize;\r
3054         }\r
3055     }\r
3056 \r
3057     if( hdc != NULL ) {\r
3058         DeleteDC( hdc );\r
3059     }\r
3060 \r
3061     if( hdc_window != NULL ) {\r
3062         ReleaseDC( hwndMain, hdc_window );\r
3063     }\r
3064 }\r
3065 \r
3066 HBITMAP\r
3067 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)\r
3068 {\r
3069   char name[128];\r
3070 \r
3071   sprintf(name, "%s%d%s", piece, squareSize, suffix);\r
3072   if (gameInfo.event &&\r
3073       strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&\r
3074       strcmp(name, "k80s") == 0) {\r
3075     strcpy(name, "tim");\r
3076   }\r
3077   return LoadBitmap(hinst, name);\r
3078 }\r
3079 \r
3080 \r
3081 /* Insert a color into the program's logical palette\r
3082    structure.  This code assumes the given color is\r
3083    the result of the RGB or PALETTERGB macro, and it\r
3084    knows how those macros work (which is documented).\r
3085 */\r
3086 VOID\r
3087 InsertInPalette(COLORREF color)\r
3088 {\r
3089   LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);\r
3090 \r
3091   if (pLogPal->palNumEntries++ >= PALETTESIZE) {\r
3092     DisplayFatalError("Too many colors", 0, 1);\r
3093     pLogPal->palNumEntries--;\r
3094     return;\r
3095   }\r
3096 \r
3097   pe->peFlags = (char) 0;\r
3098   pe->peRed = (char) (0xFF & color);\r
3099   pe->peGreen = (char) (0xFF & (color >> 8));\r
3100   pe->peBlue = (char) (0xFF & (color >> 16));\r
3101   return;\r
3102 }\r
3103 \r
3104 \r
3105 VOID\r
3106 InitDrawingColors()\r
3107 {\r
3108   if (pLogPal == NULL) {\r
3109     /* Allocate enough memory for a logical palette with\r
3110      * PALETTESIZE entries and set the size and version fields\r
3111      * of the logical palette structure.\r
3112      */\r
3113     pLogPal = (NPLOGPALETTE)\r
3114       LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +\r
3115                               (sizeof(PALETTEENTRY) * (PALETTESIZE))));\r
3116     pLogPal->palVersion    = 0x300;\r
3117   }\r
3118   pLogPal->palNumEntries = 0;\r
3119 \r
3120   InsertInPalette(lightSquareColor);\r
3121   InsertInPalette(darkSquareColor);\r
3122   InsertInPalette(whitePieceColor);\r
3123   InsertInPalette(blackPieceColor);\r
3124   InsertInPalette(highlightSquareColor);\r
3125   InsertInPalette(premoveHighlightColor);\r
3126 \r
3127   /*  create a logical color palette according the information\r
3128    *  in the LOGPALETTE structure.\r
3129    */\r
3130   hPal = CreatePalette((LPLOGPALETTE) pLogPal);\r
3131 \r
3132   lightSquareBrush = CreateSolidBrush(lightSquareColor);\r
3133   blackSquareBrush = CreateSolidBrush(blackPieceColor);\r
3134   darkSquareBrush = CreateSolidBrush(darkSquareColor);\r
3135   whitePieceBrush = CreateSolidBrush(whitePieceColor);\r
3136   blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
3137   iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));\r
3138   explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic\r
3139   /* [AS] Force rendering of the font-based pieces */\r
3140   if( fontBitmapSquareSize > 0 ) {\r
3141     fontBitmapSquareSize = 0;\r
3142   }\r
3143 }\r
3144 \r
3145 \r
3146 int\r
3147 BoardWidth(int boardSize, int n)\r
3148 { /* [HGM] argument n added to allow different width and height */\r
3149   int lineGap = sizeInfo[boardSize].lineGap;\r
3150 \r
3151   if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {\r
3152       lineGap = appData.overrideLineGap;\r
3153   }\r
3154 \r
3155   return (n + 1) * lineGap +\r
3156           n * sizeInfo[boardSize].squareSize;\r
3157 }\r
3158 \r
3159 /* Respond to board resize by dragging edge */\r
3160 VOID\r
3161 ResizeBoard(int newSizeX, int newSizeY, int flags)\r
3162 {\r
3163   BoardSize newSize = NUM_SIZES - 1;\r
3164   static int recurse = 0;\r
3165   if (IsIconic(hwndMain)) return;\r
3166   if (recurse > 0) return;\r
3167   recurse++;\r
3168   while (newSize > 0) {\r
3169         InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects\r
3170         if(newSizeX >= sizeInfo[newSize].cliWidth &&\r
3171            newSizeY >= sizeInfo[newSize].cliHeight) break;\r
3172     newSize--;\r
3173   } \r
3174   boardSize = newSize;\r
3175   InitDrawingSizes(boardSize, flags);\r
3176   recurse--;\r
3177 }\r
3178 \r
3179 \r
3180 \r
3181 VOID\r
3182 InitDrawingSizes(BoardSize boardSize, int flags)\r
3183 {\r
3184   int i, boardWidth, boardHeight; /* [HGM] height treated separately */\r
3185   ChessSquare piece;\r
3186   static int oldBoardSize = -1, oldTinyLayout = 0;\r
3187   HDC hdc;\r
3188   SIZE clockSize, messageSize;\r
3189   HFONT oldFont;\r
3190   char buf[MSG_SIZ];\r
3191   char *str;\r
3192   HMENU hmenu = GetMenu(hwndMain);\r
3193   RECT crect, wrect, oldRect;\r
3194   int offby;\r
3195   LOGBRUSH logbrush;\r
3196 \r