Fix buffer overflow in parser
[xboard.git] / winboard / wsettings.c
index 65f9e78..2cce2e0 100644 (file)
@@ -473,10 +473,11 @@ LRESULT CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lPa
                          char filter[] =\r
                                "All files\0*.*\0Game files\0*.pgn;*.gam\0Position files\0*.fen;*.epd;*.pos\0"\r
                                "EXE files\0*.exe\0Tournament files (*.trn)\0*.trn\0"\r
-                               "BIN Files\0*.bin\0LOG Files\0*.log\0INI Files\0*.ini\0\0";\r
+                               "BIN Files\0*.bin\0LOG Files\0*.log\0INI Files\0*.ini\0"\r
+                               "Image files\0*.bmp\0\0";\r
                          OPENFILENAME ofn;\r
 \r
-                         safeStrCpy( buf, "" , sizeof( buf)/sizeof( buf[0]) );\r
+                         GetDlgItemText( hDlg, i+3, buf, MSG_SIZ );\r
 \r
                          ZeroMemory( &ofn, sizeof(ofn) );\r
 \r
@@ -498,6 +499,7 @@ LRESULT CALLBACK SettingsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lPa
                          }\r
                } else\r
                if(j == -3) {\r
+                   GetDlgItemText( hDlg, i+3, buf, MSG_SIZ );\r
                    if( BrowseForFolder( _("Choose Folder:"), buf ) ) {\r
                        SetDlgItemText( hDlg, i+3, buf );\r
                    }\r
@@ -549,13 +551,15 @@ void AddControl(int x, int y, int w, int h, int type, int style, int n)
 \r
 void AddOption(int x, int y, Control type, int i)\r
 {\r
-    int extra;\r
+    int extra, num = ES_NUMBER;\r
 \r
     switch(type) {\r
+       case Slider+100:\r
+           num = 0; // needs text control for accepting negative numbers\r
        case Slider:\r
        case Spin:\r
            AddControl(x, y+1, 95, 9, 0x0082, SS_ENDELLIPSIS | WS_VISIBLE | WS_CHILD, i);\r
-           AddControl(x+95, y, 50, 11, 0x0081, ES_AUTOHSCROLL | ES_NUMBER | WS_BORDER | WS_VISIBLE | WS_CHILD | WS_TABSTOP, i+1);\r
+           AddControl(x+95, y, 50, 11, 0x0081, ES_AUTOHSCROLL | num | WS_BORDER | WS_VISIBLE | WS_CHILD | WS_TABSTOP, i+1);\r
            break;\r
        case TextBox:\r
            extra = 13*activeList[layoutList[i/2]].min; // when extra high, left-align and put description text above it\r
@@ -623,7 +627,8 @@ CreateDialogTemplate(int *layoutList, int nr, Option *optionList)
        }\r
        j = layoutList[i];\r
        if(j >= 0) {\r
-           AddOption(x+155-150*(i&1), y+13*(i>>1)+5, optionList[j].type, 2*i);\r
+           int neg = (optionList[j].type == Spin && optionList[j].min < 0 ? 100 : 0); // flags spin with negative range\r
+           AddOption(x+155-150*(i&1), y+13*(i>>1)+5, optionList[j].type + neg, 2*i);\r
            // listboxes have the special power to adjust the width of the column they are in\r
            if(optionList[j].type == ListBox) x -= optionList[j].value, template.header.cx -= optionList[j].value;\r
        }\r
@@ -757,12 +762,98 @@ void LoadEnginePopUp(HWND hwnd, int nr)
     GenericPopup(hwnd, installOptions);\r
 }\r
 \r
+int PickTheme P((HWND hDlg));\r
+void DeleteTheme P((HWND hDlg));\r
+\r
+int ThemeOK()\r
+{\r
+    if(selected >= 0) { ASSIGN(engineLine, engineList[selected]); }\r
+    if(engineLine[0] == '#') { DisplayError(_("Select single theme from the group"), 0); return 0; }\r
+    LoadTheme();\r
+    return 1;\r
+}\r
+\r
+Option themeOptions[] = {\r
+  { 195, 14,    0, NULL, (void*) &PickTheme, (char*) &selected, engineMnemonic, ListBox, N_("Select theme from list:") },\r
+  {   0,  0,    0, NULL, NULL, NULL, NULL, Label, N_("or specify new theme below:") },\r
+  {   0,  0,    0, NULL, (void*) &nickName, NULL, NULL, TextBox, N_("Theme name:") },\r
+  {   0,  0,    0, NULL, (void*) &appData.useBitmaps, NULL, NULL, CheckBox, N_("Use board textures") },\r
+  {   0,  0, 32+0, NULL, (void*) &appData.liteBackTextureFile, NULL, NULL, FileName, N_("Light-square texture:") },\r
+  {   0,  0, 32+0, NULL, (void*) &appData.darkBackTextureFile, NULL, NULL, FileName, N_("Dark-square texture:") },\r
+  {   0,  0,    3, NULL, (void*) &appData.darkBackTextureMode, "", NULL, Spin, N_("Dark reorientation mode:") },\r
+  {   0,  0,    3, NULL, (void*) &appData.liteBackTextureMode, "", NULL, Spin, N_("Light reorientation mode:") },\r
+  {   0,  0,    0, NULL, (void*) &appData.useBorder, NULL, NULL, CheckBox, N_("Draw border around board") },\r
+  {   0,  0, 32+0, NULL, (void*) &appData.border, NULL, NULL, FileName, N_("Optional border bitmap:") },\r
+  {   0,  0,    0, NULL, NULL, NULL, NULL, Label, N_("        Beware: a specified piece font will prevail over piece bitmaps") },\r
+  {   0,  0,    0, NULL, (void*) &appData.pieceDirectory, NULL, NULL, PathName, N_("Directory with piece bitmaps:") },\r
+  {   0,  0,    0, NULL, (void*) &appData.useFont, NULL, NULL, CheckBox, N_("Use piece font") },\r
+  {   0, 50,  150, NULL, (void*) &appData.fontPieceSize, "", NULL, Spin, N_("Font size (%):") },\r
+  {   0,  0,    0, NULL, (void*) &appData.renderPiecesWithFont, NULL, NULL, TextBox, N_("Font name:") },\r
+  {   0,  0,    0, NULL, (void*) &appData.fontToPieceTable, NULL, NULL, TextBox, N_("Font piece to char:") },\r
+//  {   0,  0,    0, NULL, (void*) &DeleteTheme, NULL, NULL, Button, N_("Up") },\r
+//  {   0,  0,    0, NULL, (void*) &DeleteTheme, NULL, NULL, Button, N_("Down") },\r
+  {   0,  0,    0, NULL, (void*) &DeleteTheme, NULL, NULL, Button, N_("Delete Theme") },\r
+  {   0,  1,    0, NULL, (void*) &ThemeOK, "", NULL, EndMark , "" }\r
+};\r
+\r
+void\r
+DeleteTheme (HWND hDlg)\r
+{\r
+    char *p, *q;\r
+    int i, selected = SendDlgItemMessage(hDlg, 2001+2*1, LB_GETCURSEL, 0, 0);\r
+    HANDLE hwndCombo = GetDlgItem(hDlg, 2001+2*1);\r
+    if(selected < 0) return;\r
+    if(p = strstr(appData.themeNames, engineList[selected])) {\r
+       if(q = strchr(p, '\n')) strcpy(p, q+1);\r
+    }\r
+    themeOptions[0].max = NamesToList(appData.themeNames, engineList, engineMnemonic, ""); // replace list by only the group contents\r
+    SendMessage(hwndCombo, LB_RESETCONTENT, 0, 0);\r
+    SendMessage(hwndCombo, LB_ADDSTRING, 0, (LPARAM) "");\r
+    for(i=1; i<themeOptions[0].max; i++) {\r
+           SendMessage(hwndCombo, LB_ADDSTRING, 0, (LPARAM) engineMnemonic[i]);\r
+    }\r
+}\r
+\r
+int\r
+PickTheme (HWND hDlg)\r
+{\r
+    char buf[MSG_SIZ];\r
+    HANDLE hwndCombo = GetDlgItem(hDlg, 2001+2*1);\r
+    int i = SendDlgItemMessage(hDlg, 2001+2*1, LB_GETCURSEL, 0, 0);\r
+    if(i == 0) buf[0] = NULLCHAR; // back to top level\r
+    else if(engineList[i][0] == '#') safeStrCpy(buf, engineList[i], MSG_SIZ); // group header, open group\r
+    else {\r
+       ASSIGN(engineLine, engineList[i]);\r
+       LoadTheme();\r
+       EndDialog( hDlg, 0 );\r
+       return 0; // normal line, select engine\r
+    }\r
+    themeOptions[0].max = NamesToList(appData.themeNames, engineList, engineMnemonic, buf); // replace list by only the group contents\r
+    SendMessage(hwndCombo, LB_RESETCONTENT, 0, 0);\r
+    SendMessage(hwndCombo, LB_ADDSTRING, 0, (LPARAM) buf);\r
+    for(i=1; i<themeOptions[0].max; i++) {\r
+           SendMessage(hwndCombo, LB_ADDSTRING, 0, (LPARAM) engineMnemonic[i]);\r
+    }\r
+    return 0;\r
+}\r
+\r
+void ThemeOptionsPopup(HWND hwnd)\r
+{\r
+    addToList = TRUE; // defaults\r
+    if(nickName)     free(nickName);     nickName = strdup("");\r
+    if(engineLine)   free(engineLine);   engineLine = strdup("");\r
+    themeOptions[0].max = NamesToList(appData.themeNames, engineList, engineMnemonic, ""); // only top level\r
+    snprintf(title, MSG_SIZ, _("Board themes"));\r
+\r
+    GenericPopup(hwnd, themeOptions);\r
+}\r
+\r
 Boolean autoinc, twice, swiss;\r
 char *tfName;\r
 \r
 int MatchOK()\r
 {\r
-    if(autoinc) appData.loadGameIndex = appData.loadPositionIndex = -(twice + 1);\r
+    if(autoinc) appData.loadGameIndex = appData.loadPositionIndex = -(twice + 1); else\r
     if(!appData.loadGameFile[0]) appData.loadGameIndex = -2*twice; // kludge to pass value of "twice" for use in GUI book\r
     if(swiss) { appData.defaultMatchGames = 1; appData.tourneyType = -1; }\r
     if(CreateTourney(tfName) && !matchMode) { // CreateTourney reloads original settings if file already existed\r
@@ -772,6 +863,19 @@ int MatchOK()
     return matchMode || !appData.participants[0]; // if we failed to create and are not in playing, forbid popdown if there are participants\r
 }\r
 \r
+void PseudoOK(HWND hDlg)\r
+{\r
+    void (*saveOK)();\r
+    saveOK = okFunc; okFunc = 0;\r
+    GetOptionValues(hDlg, activeCps, activeList);\r
+    EndDialog( hDlg, 0 );\r
+    comboCallback = NULL; activeCps = NULL;\r
+\r
+    if(autoinc) appData.loadGameIndex = appData.loadPositionIndex = -(twice + 1); else\r
+    if(!appData.loadGameFile[0]) appData.loadGameIndex = -2*twice; // kludge to pass value of "twice" for use in GUI book\r
+    if(swiss) { appData.defaultMatchGames = 1; appData.tourneyType = -1; }\r
+}\r
+\r
 char *GetParticipants(HWND hDlg)\r
 {\r
     int len = GetWindowTextLength(GetDlgItem(hDlg, 2001+2*0)) + 1;\r
@@ -844,6 +948,7 @@ Option tourneyOptions[] = {
   { 0,  0,          0, NULL, (void*) &TimeControlOptionsPopup, "", NULL, Button, N_("Time Control...") },\r
   { 0,  0,          0, NULL, (void*) &UciOptionsPopup, "", NULL, Button, N_("Common Engine...") },\r
   { 0,  0,          0, NULL, (void*) &Inspect, "", NULL, Button, N_("Clone Tourney") },\r
+  { 0,  0,          0, NULL, (void*) &PseudoOK, "", NULL, Button, N_("Continue Later") },\r
   { 0, 0, 0, NULL, (void*) &MatchOK, "", NULL, EndMark , "" }\r
 };\r
 \r
@@ -875,7 +980,7 @@ void TourneyPopup(HWND hwnd)
 {\r
     int n = NamesToList(firstChessProgramNames, engineList, engineMnemonic, "");\r
     autoinc = appData.loadGameIndex < 0 || appData.loadPositionIndex < 0;\r
-    twice = FALSE; swiss = appData.tourneyType < 0;\r
+    twice = appData.loadGameIndex == -2 || appData.loadPositionIndex == -2; swiss = appData.tourneyType < 0;\r
     tourneyOptions[0].max = n;\r
     snprintf(title, MSG_SIZ, _("Tournament and Match Options"));\r
     ASSIGN(tfName, appData.tourneyFile[0] ? appData.tourneyFile : MakeName(appData.defName));\r