- // config.cpp 
-   
- #include "common.h" 
-   
-   
- // useful macros 
- #define READ_WIDESTRING(dest,inifile,section,key,default_value) wcscpy_s ((dest), sizeof (dest) / sizeof (wchar_t), INIFile_ReadEntryAsString ((inifile), (section), (key), (default_value))) 
- #define WRITE_WIDESTRING(section,key,value) INIFile_WriteEntryAsString (inifile, (section), (key), (value)) 
-   
-   
- // global variables used in this module only 
- static wchar_t filename[MAX_PATH]; 
-   
-   
- void Config_Load (void) 
- { 
-    // this function opens and parses the INI configuration file for the program 
-    // WARNING: it does also build the smilies list ! 
-   
-    void *inifile; 
-    smiley_t *smiley; 
-    char *file_buffer; 
-    wchar_t language_name[64]; 
-    wchar_t smiley_pathname[MAX_PATH]; 
-    wchar_t *smiley_name; 
-    int language_index; 
-    int smiley_index; 
-    int file_length; 
-    FILE *fp; 
-   
-    // open the INI file 
-    swprintf_s (filename, WCHAR_SIZEOF (filename), L"%s/config.ini", app_path); 
-    inifile = INIFile_LoadINIFile (filename); 
-   
-    // read the INI file (if it doesn't exist, default values will be fed) 
-   
-    // [gameplay] 
-    options.want_lastmove = (INIFile_ReadEntryAsBool (inifile, L"options", L"highlight last move", true) > 0); 
-    options.want_possiblemoves = (INIFile_ReadEntryAsBool (inifile, L"options", L"highlight possible moves", true) > 0); 
-    options.want_threats = (INIFile_ReadEntryAsBool (inifile, L"options", L"highlight king's threats", true) > 0); 
-    options.want_animations = (INIFile_ReadEntryAsBool (inifile, L"options", L"display part animations", true) > 0); 
-    options.want_takenparts = (INIFile_ReadEntryAsBool (inifile, L"options", L"show taken parts", true) > 0); 
-    options.want_turn = (INIFile_ReadEntryAsBool (inifile, L"options", L"show turn", true) > 0); 
-    options.want_clock = (INIFile_ReadEntryAsBool (inifile, L"options", L"show game clock", true) > 0); 
-    options.clock_color = INIFile_ReadEntryAsUnsignedLong (inifile, L"options", L"game clock color", 0x00007f00); // dark blue, in RGBA 
-    options.want_history = (INIFile_ReadEntryAsBool (inifile, L"options", L"show game history", true) > 0); 
-    options.history_color = INIFile_ReadEntryAsUnsignedLong (inifile, L"options", L"game history color", 0xe7e7e700); // light grey, in RGBA 
-    options.want_sepiafilter = (INIFile_ReadEntryAsBool (inifile, L"options", L"use sepia filter for past moves", true) > 0); 
-    options.want_autorotateon1vs1 = (INIFile_ReadEntryAsBool (inifile, L"options", L"auto-rotate board",true) > 0); 
-    options.rotate_speed = INIFile_ReadEntryAsLong (inifile, L"options", L"rotation speed", 5); 
-   
-    // [display] 
-    READ_WIDESTRING (language_name, inifile, L"display", L"language", L"auto"); // first, try to read the language from the config file 
-    for (language_index = 0; language_index < language_count; language_index++) 
-       if (_wcsicmp (languages[language_index].name, language_name) == 0) 
-       { 
-          language_id = language_index; // identify the claimed language's ID among the list of known languages 
-          break; // stop searching as soon as we find it 
-       } 
-    if (language_index == language_count) 
-    { 
-       GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SENGLANGUAGE, language_name, WCHAR_SIZEOF (language_name)); // if unspecified, query the OS locale 
-       for (language_index = 0; language_index < language_count; language_index++) 
-          if (_wcsicmp (languages[language_index].name, language_name) == 0) 
-          { 
-             language_id = language_index; // identify the claimed language's ID among the list of known languages 
-             break; // stop searching as soon as we find it 
-          } 
-    } 
-    if (language_index == language_count) 
-    { 
-       for (language_index = 0; language_index < language_count; language_index++) 
-          if (_wcsicmp (languages[language_index].name, L"English") == 0) 
-          { 
-             language_id = language_index; // if still not found, fallback to the English language 
-             break; // stop searching as soon as we find it 
-          } 
-    } 
-    if (language_index == language_count) 
-       language_id = 0; // if still not found, fallback to the first language known 
-    options.want_fullscreen = (INIFile_ReadEntryAsBool (inifile, L"display", L"fullscreen", false) > 0); 
-    options.window_width = INIFile_ReadEntryAsLong (inifile, L"display", L"window width", 1024); 
-    options.window_height = INIFile_ReadEntryAsLong (inifile, L"display", L"window height", 768); 
-    options.want_filtering = (INIFile_ReadEntryAsBool (inifile, L"display", L"enable texture filtering", true) > 0); 
-    options.want_hiquality = (INIFile_ReadEntryAsBool (inifile, L"display", L"enable high quality filtering", true) > 0); 
-    options.want_specularlighting = (INIFile_ReadEntryAsBool (inifile, L"display", L"enable specular lighting", true) > 0); 
-    options.want_reflections = (INIFile_ReadEntryAsBool (inifile, L"display", L"enable board reflections", true) > 0); 
-   
-    // [sound] 
-    options.want_sounds = (INIFile_ReadEntryAsBool (inifile, L"sound", L"play sounds", true) > 0); 
-   
-    // [theme] 
-    READ_WIDESTRING (wantedtheme_name, inifile, L"theme", L"theme name", L"Marble"); 
-    want_grid = (INIFile_ReadEntryAsBool (inifile, L"theme", L"show grid", false) > 0); 
-    want_flaticons = (INIFile_ReadEntryAsBool (inifile, L"theme", L"flat icons instead", false) > 0); 
-    want_custombackground = (INIFile_ReadEntryAsBool (inifile, L"theme", L"use custom background", false) > 0); 
-    READ_WIDESTRING (custombackground_pathname, inifile, L"theme", L"custom background picture", L""); 
-   
-    // [engine] 
-    READ_WIDESTRING (options.engine.program, inifile, L"engine", L"program", L"Crafty"); 
-    options.engine.depth = INIFile_ReadEntryAsLong (inifile, L"engine", L"allowed depth", 4); 
-    options.engine.max_depth = INIFile_ReadEntryAsLong (inifile, L"engine", L"maximum depth", 100); 
-    options.engine.blunder_chances = INIFile_ReadEntryAsLong (inifile, L"engine", L"blunder chances", 0); 
-    options.engine.obstinacy_level = INIFile_ReadEntryAsLong (inifile, L"engine", L"obstinacy", 0); 
-    options.engine.is_expert_mode = (INIFile_ReadEntryAsBool (inifile, L"engine", L"expert mode", false) > 0); 
-   
-    // [network] 
-    READ_WIDESTRING (options.network.server_address, inifile, L"network", L"server address", L"freechess.org"); 
-    options.network.server_port = INIFile_ReadEntryAsLong (inifile, L"network", L"server port", 5000); 
-    READ_WIDESTRING (options.network.login, inifile, L"network", L"login", L"guest"); 
-    READ_WIDESTRING (options.network.password, inifile, L"network", L"password", L""); 
-    options.network.want_servermessages = (INIFile_ReadEntryAsBool (inifile, L"network", L"show server messages", true) > 0); 
-    options.network.want_publicchat = (INIFile_ReadEntryAsBool (inifile, L"network", L"show public chat", true) > 0); 
-    options.network.want_motdonconnect = (INIFile_ReadEntryAsBool (inifile, L"network", L"show MOTD on connect", true) > 0); 
-   
-    // [registration] 
-    READ_WIDESTRING (options.registration.user_email, inifile, L"registration", L"user email", L""); 
-    options.registration.activation_code = (unsigned __int32) INIFile_ReadEntryAsLong (inifile, L"registration", L"activation code", 0); 
-   
-    // [smilies] 
-    smilies = NULL; 
-    smiley_count = 0; 
-    while ((smiley_name = INIFile_GetEntryName (inifile, L"smilies", smiley_count)) != NULL) 
-    { 
-       // for each smiley we can read, reallocate smilies array to hold one smiley more 
-       smilies = (smiley_t *) SAFE_realloc (smilies, smiley_count, smiley_count + 1, sizeof (smiley_t), false); 
-   
-       smiley = &smilies[smiley_count]; // quick access to smiley 
-   
-       // read the smiley name and convert quotes to spaces 
-       wcscpy_s (smiley->name, WCHAR_SIZEOF (smiley->name), smiley_name); 
-       smiley->name[0] = L' '; // convert leading quote to a space 
-       smiley->name[wcslen (smiley->name) - 1] = L' '; // convert ending quote to a space 
-   
-       // now read the smiley's corresponding picture file 
-       READ_WIDESTRING (smiley->filename, inifile, L"smilies", smiley_name, L"smile.wmf"); 
-   
-       // is this filename the same as another smiley we know already ? 
-       for (smiley_index = 0; smiley_index < smiley_count; smiley_index++) 
-          if (wcscmp (smilies[smiley_index].filename, smiley->filename) == 0) 
-             break; // break as soon as we find a match 
-   
-       // did we find a match ? 
-       if (smiley_index < smiley_count) 
-       { 
-          // if so, just copy data and data length from the smiley we already know 
-          smiley->rtf_data = smilies[smiley_index].rtf_data; 
-          smiley->rtf_len = smilies[smiley_index].rtf_len; 
-       } 
-   
-       // else we found no match, we have to read the file ourselves 
-       else 
-       { 
-          // build the smiley picture's file pathname and read that smiley's data as a hex string 
-          swprintf_s (smiley_pathname, WCHAR_SIZEOF (smiley_pathname), L"%s/data/smilies/%s", app_path, smiley->filename); 
-          _wfopen_s (&fp, smiley_pathname, L"rb"); 
-          if (fp == NULL) 
-             continue; // if this smiley picture file can't be opened, ignore this smiley 
-   
-          // get the file length 
-          fseek (fp, 0, SEEK_END); 
-          file_length = ftell (fp); 
-          fseek (fp, 0, SEEK_SET); 
-   
-          // mallocate space for file contents and read it 
-          file_buffer = (char *) SAFE_malloc (1 + file_length + 1 + 1, sizeof (char), false); // include null terminator 
-          file_buffer[0] = ' '; // first character is a whitespace 
-          fread (&file_buffer[1], file_length, sizeof (char), fp); 
-          file_buffer[1 + file_length] = ' '; // last character is a whitespace 
-          file_buffer[1 + file_length + 1] = 0; // terminate the char string 
-          fclose (fp); // finished with the smiley picture file 
-   
-          // convert it to wide char 
-          smiley->rtf_len = 1 + file_length + 1; 
-          smiley->rtf_data = (wchar_t *) SAFE_malloc (smiley->rtf_len + 1, sizeof (wchar_t), false); // include null terminator 
-          ConvertToWideChar (smiley->rtf_data, smiley->rtf_len + 1, file_buffer); 
-          SAFE_free ((void **) &file_buffer); 
-       } 
-   
-       smiley_count++; // we know now one smiley more 
-    } 
-   
-    // close the INI file 
-    INIFile_FreeINIFile (inifile); 
-    return; // finished loading config 
- } 
-   
-   
- void Config_LoadEngine (const wchar_t *engine_name) 
- { 
-    // this function loads the engine-specific parameters. The best place to call it is at the beginning 
-    // of a game versus the computer, just before the engine executable process is started. 
-   
-    void *engine_inifile; 
-    wchar_t *ptr; 
-   
-    // reset values first 
-    memset (&options.engine.program_options, 0, sizeof (options.engine.program_options)); 
-   
-    // given the selected engine program, load and interpret the right engine config file 
-    swprintf_s (filename, WCHAR_SIZEOF (filename), L"%s/engines/%s/engine.ini", app_path, engine_name); 
-    engine_inifile = INIFile_LoadINIFile (filename); 
-    if (engine_inifile == NULL) 
-       return; // engine file not found 
-   
-    // basic program information 
-    READ_WIDESTRING (options.engine.program_options.name, engine_inifile, L"program", L"name", L"Crafty v24.0"); 
-    READ_WIDESTRING (options.engine.program_options.cmdline, engine_inifile, L"program", L"executable", L"crafty.exe"); 
-   
-    // reply string patterns 
-    READ_WIDESTRING (options.engine.program_options.replystring_move, engine_inifile, L"reply strings", L"move", L"): "); 
-   
-    // engine commands 
-    READ_WIDESTRING (options.engine.program_options.command_new, engine_inifile, L"commands", L"new game", L"new"); 
-    for (ptr = options.engine.program_options.command_new; *ptr != 0; ptr++) if (*ptr == L';') *ptr = L'\n'; 
-    READ_WIDESTRING (options.engine.program_options.command_setboard, engine_inifile, L"commands", L"setup table from FEN", L"setboard %s"); 
-    for (ptr = options.engine.program_options.command_setboard; *ptr != 0; ptr++) if (*ptr == L';') *ptr = L'\n'; 
-    READ_WIDESTRING (options.engine.program_options.command_sd, engine_inifile, L"commands", L"search depth set", L"sd %d"); 
-    for (ptr = options.engine.program_options.command_sd; *ptr != 0; ptr++) if (*ptr == L';') *ptr = L'\n'; 
-    READ_WIDESTRING (options.engine.program_options.command_go, engine_inifile, L"commands", L"play", L"go"); 
-    for (ptr = options.engine.program_options.command_go; *ptr != 0; ptr++) if (*ptr == L';') *ptr = L'\n'; 
-    READ_WIDESTRING (options.engine.program_options.command_move, engine_inifile, L"commands", L"move", L"%s"); 
-    for (ptr = options.engine.program_options.command_move; *ptr != 0; ptr++) if (*ptr == L';') *ptr = L'\n'; 
-    READ_WIDESTRING (options.engine.program_options.command_force, engine_inifile, L"commands", L"force move", L"force %s"); 
-    for (ptr = options.engine.program_options.command_force; *ptr != 0; ptr++) if (*ptr == L';') *ptr = L'\n'; 
-    READ_WIDESTRING (options.engine.program_options.command_quit, engine_inifile, L"commands", L"quit", L"quit"); 
-    for (ptr = options.engine.program_options.command_quit; *ptr != 0; ptr++) if (*ptr == L';') *ptr = L'\n'; 
-   
-    INIFile_FreeINIFile (engine_inifile); // close the engine config file 
-    return; // engine parameters loaded successfully 
- } 
-   
-   
- void Config_Save (void) 
- { 
-    // this function saves the software configuration into an INI file. 
-    // WARNING: it does also free the smilies list ! 
-   
-    wchar_t smiley_name[32]; 
-    smiley_t *smiley; 
-    void *inifile; 
-    int smiley_index; 
-    int smiley_index2; 
-   
-    // create a config file with the default values 
-    inifile = INIFile_NewINIFile (); 
-   
-    // [gameplay] 
-    INIFile_WriteEntryAsBool (inifile, L"options", L"highlight last move", options.want_lastmove); 
-    INIFile_WriteEntryAsBool (inifile, L"options", L"highlight possible moves", options.want_possiblemoves); 
-    INIFile_WriteEntryAsBool (inifile, L"options", L"highlight king's threats", options.want_threats); 
-    INIFile_WriteEntryAsBool (inifile, L"options", L"display part animations", options.want_animations); 
-    INIFile_WriteEntryAsBool (inifile, L"options", L"show taken parts", options.want_takenparts); 
-    INIFile_WriteEntryAsBool (inifile, L"options", L"show turn", options.want_turn); 
-    INIFile_WriteEntryAsBool (inifile, L"options", L"show game clock", options.want_clock); 
-    INIFile_WriteEntryAsUnsignedLong (inifile, L"options", L"game clock color", options.clock_color); 
-    INIFile_WriteEntryAsBool (inifile, L"options", L"show game history", options.want_history); 
-    INIFile_WriteEntryAsUnsignedLong (inifile, L"options", L"game history color", options.history_color); 
-    INIFile_WriteEntryAsBool (inifile, L"options", L"use sepia filter for past moves", options.want_sepiafilter); 
-    INIFile_WriteEntryAsBool (inifile, L"options", L"auto-rotate board", options.want_autorotateon1vs1); 
-    INIFile_WriteEntryAsLong (inifile, L"options", L"rotation speed", options.rotate_speed); 
-   
-    // [display] 
-    WRITE_WIDESTRING (L"display", L"language", languages[language_id].name); 
-    INIFile_WriteEntryAsBool (inifile, L"display", L"fullscreen", options.want_fullscreen); 
-    INIFile_WriteEntryAsLong (inifile, L"display", L"window width", max (options.window_width, 640)); 
-    INIFile_WriteEntryAsLong (inifile, L"display", L"window height", max (options.window_height, 480)); 
-    INIFile_WriteEntryAsBool (inifile, L"display", L"enable texture filtering", options.want_filtering); 
-    INIFile_WriteEntryAsBool (inifile, L"display", L"enable high quality filtering", options.want_hiquality); 
-    INIFile_WriteEntryAsBool (inifile, L"display", L"enable specular lighting", options.want_specularlighting); 
-    INIFile_WriteEntryAsBool (inifile, L"display", L"enable board reflections", options.want_reflections); 
-   
-    // [sound] 
-    INIFile_WriteEntryAsBool (inifile, L"sound", L"play sounds", options.want_sounds); 
-   
-    // [theme] 
-    WRITE_WIDESTRING (L"theme", L"theme name", (wantedtheme_name[0] != 0 ? wantedtheme_name : L"Marble")); 
-    INIFile_WriteEntryAsBool (inifile, L"theme", L"show grid", want_grid); 
-    INIFile_WriteEntryAsBool (inifile, L"theme", L"flat icons instead", want_flaticons); 
-    INIFile_WriteEntryAsBool (inifile, L"theme", L"use custom background", want_custombackground); 
-    WRITE_WIDESTRING (L"theme", L"custom background picture", custombackground_pathname); 
-   
-    // [engine] 
-    WRITE_WIDESTRING (L"engine", L"program", options.engine.program); 
-    INIFile_WriteEntryAsLong (inifile, L"engine", L"allowed depth", options.engine.depth); 
-    INIFile_WriteEntryAsLong (inifile, L"engine", L"maximum depth", options.engine.max_depth); 
-    INIFile_WriteEntryAsLong (inifile, L"engine", L"blunder chances", options.engine.blunder_chances); 
-    INIFile_WriteEntryAsLong (inifile, L"engine", L"obstinacy", options.engine.obstinacy_level); 
-    INIFile_WriteEntryAsBool (inifile, L"engine", L"expert mode", options.engine.is_expert_mode); 
-   
-    // [network] 
-    WRITE_WIDESTRING (L"network", L"server address", options.network.server_address); 
-    INIFile_WriteEntryAsLong (inifile, L"network", L"server port", options.network.server_port); 
-    WRITE_WIDESTRING (L"network", L"login", options.network.login); 
-    WRITE_WIDESTRING (L"network", L"password", options.network.password); 
-    INIFile_WriteEntryAsBool (inifile, L"network", L"show server messages", options.network.want_servermessages); 
-    INIFile_WriteEntryAsBool (inifile, L"network", L"show public chat", options.network.want_publicchat); 
-    INIFile_WriteEntryAsBool (inifile, L"network", L"show MOTD on connect", options.network.want_motdonconnect); 
-   
-    // [registration] 
-    WRITE_WIDESTRING (L"registration", L"user email", options.registration.user_email); 
-    INIFile_WriteEntryAsLong (inifile, L"registration", L"activation code", (long) options.registration.activation_code); 
-   
-    // [smilies] 
-    for (smiley_index = 0; smiley_index < smiley_count; smiley_index++) 
-    { 
-       smiley = &smilies[smiley_index]; // quick access to smiley 
-   
-       // have a copy of the smiley's name and convert spaces back to quotes before saving them 
-       wcscpy_s (smiley_name, WCHAR_SIZEOF (smiley_name), smiley->name); 
-       smiley_name[0] = L'"'; // convert leading space to a quote 
-       smiley_name[wcslen (smiley_name) - 1] = L'"'; // convert ending space to a quote 
-       WRITE_WIDESTRING (L"smilies", smiley_name, smiley->filename); 
-   
-       // cycle through all the other smileys to see if another one uses the same data... 
-       for (smiley_index2 = smiley_index; smiley_index2 < smiley_count; smiley_index2++) 
-          if (smilies[smiley_index2].rtf_data == smiley->rtf_data) 
-             break; // break as soon as we find one that uses the same data 
-       if (smiley_index2 == smiley_count) 
-          SAFE_free ((void **) &smiley->rtf_data); // only free data when we find none 
-    } 
-    SAFE_free ((void **) &smilies); 
-    smiley_count = 0; 
-   
-    // now save the INI file 
-    swprintf_s (filename, WCHAR_SIZEOF (filename), L"%s/config.ini", app_path); 
-    INIFile_SaveINIFile (filename, inifile); 
-   
-    return; // finished 
- } 
-