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