EXPORT m64p_error CALL ConfigDeleteSection(const char *SectionName) { config_section *curr_section; config_var *curr_var; if (!l_ConfigInit) return M64ERR_NOT_INIT; if (l_ConfigListActive == NULL) return M64ERR_INPUT_NOT_FOUND; /* find the named section and pull it out of the list */ curr_section = l_ConfigListActive; if (osal_insensitive_strcmp(l_ConfigListActive->name, SectionName) == 0) { l_ConfigListActive = l_ConfigListActive->next; } else { while (curr_section != NULL) { config_section *next_section = curr_section->next; if (next_section == NULL) return M64ERR_INPUT_NOT_FOUND; if (osal_insensitive_strcmp(next_section->name, SectionName) == 0) { curr_section->next = next_section->next; curr_section = next_section; break; } curr_section = next_section; } } /* delete all the variables in this section */ curr_var = curr_section->first_var; while (curr_var != NULL) { config_var *next_var = curr_var->next; if (curr_var->val_string != NULL) free(curr_var->val_string); if (curr_var->comment != NULL) free(curr_var->comment); free(curr_var); curr_var = next_var; } /* delete the section itself */ free(curr_section); return M64ERR_SUCCESS; }
EXPORT m64p_error CALL ConfigOpenSection(const char *SectionName, m64p_handle *ConfigSectionHandle) { config_section *curr_section, *new_section; if (!l_ConfigInit) return M64ERR_NOT_INIT; if (SectionName == NULL || ConfigSectionHandle == NULL) return M64ERR_INPUT_ASSERT; /* walk through the section list, looking for a case-insensitive name match */ curr_section = l_ConfigListActive; while (curr_section != NULL) { if (osal_insensitive_strcmp(SectionName, curr_section->name) == 0) { *ConfigSectionHandle = curr_section; return M64ERR_SUCCESS; } curr_section = curr_section->next; } /* didn't find the section, so create new one */ new_section = (config_section *) malloc(sizeof(config_section)); if (new_section == NULL) return M64ERR_NO_MEMORY; new_section->magic = SECTION_MAGIC; strncpy(new_section->name, SectionName, 63); new_section->name[63] = 0; new_section->first_var = NULL; new_section->next = NULL; /* add section to list in alphabetical order */ if (l_ConfigListActive == NULL || osal_insensitive_strcmp(SectionName, l_ConfigListActive->name) < 0) { new_section->next = l_ConfigListActive; l_ConfigListActive = new_section; } else { curr_section = l_ConfigListActive; while (curr_section->next != NULL && osal_insensitive_strcmp(SectionName, curr_section->next->name) >= 0) curr_section = curr_section->next; new_section->next = curr_section->next; curr_section->next = new_section; } *ConfigSectionHandle = new_section; return M64ERR_SUCCESS; }
EXPORT m64p_error CALL ConfigOpenSection(const char *SectionName, m64p_handle *ConfigSectionHandle) { config_section **curr_section; config_section *new_section; if (!l_ConfigInit) return M64ERR_NOT_INIT; if (SectionName == NULL || ConfigSectionHandle == NULL) return M64ERR_INPUT_ASSERT; /* walk through the section list, looking for a case-insensitive name match */ curr_section = find_alpha_section_link(&l_ConfigListActive, SectionName); if (*curr_section != NULL && osal_insensitive_strcmp(SectionName, (*curr_section)->name) == 0) { *ConfigSectionHandle = *curr_section; return M64ERR_SUCCESS; } /* didn't find the section, so create new one */ new_section = config_section_create(SectionName); if (new_section == NULL) return M64ERR_NO_MEMORY; /* add section to list in alphabetical order */ new_section->next = *curr_section; *curr_section = new_section; *ConfigSectionHandle = new_section; return M64ERR_SUCCESS; }
EXPORT m64p_error CALL ConfigRevertChanges(const char *SectionName) { config_section *input_section, *curr_section, *new_section, *temp_next_ptr; /* check input conditions */ if (!l_ConfigInit) return M64ERR_NOT_INIT; if (SectionName == NULL) return M64ERR_INPUT_ASSERT; /* walk through the Active section list, looking for a case-insensitive name match with input string */ input_section = l_ConfigListActive; while (input_section != NULL) { if (osal_insensitive_strcmp(SectionName, input_section->name) == 0) break; input_section = input_section->next; } if (input_section == NULL) return M64ERR_INPUT_NOT_FOUND; /* walk through the Saved section list, looking for a case-insensitive name match */ curr_section = l_ConfigListSaved; while (curr_section != NULL) { if (osal_insensitive_strcmp(SectionName, curr_section->name) == 0) break; curr_section = curr_section->next; } /* if this section isn't present in saved list, then it has been newly created */ if (curr_section == NULL) return M64ERR_INPUT_NOT_FOUND; /* we need to save the "next" pointer in the active section, because this will get blown away by the deepcopy */ temp_next_ptr = input_section->next; /* delete the variables from the Active section */ delete_section_vars(input_section); /* copy all of the section data from the Saved section to the Active one */ new_section = section_deepcopy(curr_section, input_section); if (new_section == NULL) return M64ERR_NO_MEMORY; /* it's very bad if this happens, because original data from Active section has been deleted */ /* new_section should be == to input_section. now put the "next" pointer back */ input_section->next = temp_next_ptr; /* should be good to go */ return M64ERR_SUCCESS; }
EXPORT m64p_error CALL ConfigExternalGetParameter(m64p_handle Handle, const char *SectionName, const char *ParamName, char* ParamPtr, int ParamMaxLength) { struct external_config* ext_config = Handle; int foundSection = 0; if (ParamPtr == NULL || SectionName == NULL || ParamName == NULL) return M64ERR_INPUT_INVALID; void *buffer = malloc(ext_config->length + 1); memcpy(buffer, ext_config->file, ext_config->length + 1); char *line = buffer; char *end = line + ext_config->length; while (line < end) { ini_line l = ini_parse_line(&line); switch (l.type) { case INI_SECTION: if (osal_insensitive_strcmp(SectionName, l.name) == 0) foundSection = 1; else foundSection = 0; break; case INI_PROPERTY: if (foundSection) { if (osal_insensitive_strcmp(ParamName, l.name) == 0) { strncpy(ParamPtr, l.value, ParamMaxLength); free(buffer); return M64ERR_SUCCESS; } } break; default: break; } } free(buffer); return M64ERR_INPUT_NOT_FOUND; }
static config_var *find_section_var(config_section *section, const char *ParamName) { /* walk through the linked list of variables in the section */ config_var *curr_var; for (curr_var = section->first_var; curr_var != NULL; curr_var = curr_var->next) { if (osal_insensitive_strcmp(ParamName, curr_var->name) == 0) return curr_var; } /* couldn't find this configuration parameter */ return NULL; }
EXPORT int CALL ConfigGetParamBool(m64p_handle ConfigSectionHandle, const char *ParamName) { config_section *section; config_var *var; /* check input conditions */ if (!l_ConfigInit || ConfigSectionHandle == NULL || ParamName == NULL) { DebugMessage(M64MSG_ERROR, "ConfigGetParamBool(): Input assertion!"); return 0; } section = (config_section *) ConfigSectionHandle; if (section->magic != SECTION_MAGIC) { DebugMessage(M64MSG_ERROR, "ConfigGetParamBool(): ConfigSectionHandle invalid!"); return 0; } /* if this parameter doesn't already exist, return an error */ var = find_section_var(section, ParamName); if (var == NULL) { DebugMessage(M64MSG_ERROR, "ConfigGetParamBool(): Parameter '%s' not found!", ParamName); return 0; } /* translate the actual variable type to an int */ switch(var->type) { case M64TYPE_INT: return (var->val_int != 0); case M64TYPE_FLOAT: return (var->val_float != 0.0); case M64TYPE_BOOL: return var->val_int; case M64TYPE_STRING: return (osal_insensitive_strcmp(var->val_string, "true") == 0); default: DebugMessage(M64MSG_ERROR, "ConfigGetParamBool(): invalid internal parameter type for '%s'", ParamName); return 0; } return 0; }
EXPORT m64p_error CALL ConfigSaveSection(const char *SectionName) { config_section *curr_section, *new_section; config_section **insertion_point; if (!l_ConfigInit) return M64ERR_NOT_INIT; if (SectionName == NULL || strlen(SectionName) < 1) return M64ERR_INPUT_ASSERT; /* walk through the Active section list, looking for a case-insensitive name match */ curr_section = find_section(l_ConfigListActive, SectionName); if (curr_section == NULL) return M64ERR_INPUT_NOT_FOUND; /* duplicate this section */ new_section = section_deepcopy(curr_section); if (new_section == NULL) return M64ERR_NO_MEMORY; /* update config section that's in the Saved list with the new one */ insertion_point = find_alpha_section_link(&l_ConfigListSaved, SectionName); if (*insertion_point != NULL && osal_insensitive_strcmp((*insertion_point)->name, SectionName) == 0) { /* the section exists in the saved list and will be replaced */ new_section->next = (*insertion_point)->next; delete_section(*insertion_point); *insertion_point = new_section; } else { /* the section didn't exist in the saved list and has to be inserted */ new_section->next = *insertion_point; *insertion_point = new_section; } /* write the saved config list out to a file */ return (write_configlist_file()); }
EXPORT m64p_error CALL ConfigSaveSection(const char *SectionName) { config_section *curr_section, *new_section; if (!l_ConfigInit) return M64ERR_NOT_INIT; if (SectionName == NULL || strlen(SectionName) < 1) return M64ERR_INPUT_ASSERT; /* walk through the Active section list, looking for a case-insensitive name match */ curr_section = l_ConfigListActive; while (curr_section != NULL) { if (osal_insensitive_strcmp(SectionName, curr_section->name) == 0) break; curr_section = curr_section->next; } if (curr_section == NULL) return M64ERR_INPUT_NOT_FOUND; /* duplicate this section */ new_section = section_deepcopy(curr_section, NULL); if (new_section == NULL) return M64ERR_NO_MEMORY; /* update config section that's in the Saved list with the new one */ if (l_ConfigListSaved == NULL || osal_insensitive_strcmp(SectionName, l_ConfigListSaved->name) < 0) { /* the saved section is new and goes at the beginning of the list */ new_section->next = l_ConfigListSaved; l_ConfigListSaved = new_section; } else if (osal_insensitive_strcmp(SectionName, l_ConfigListSaved->name) == 0) { /* the saved section replaces the first section in the list */ new_section->next = l_ConfigListSaved->next; delete_section_vars(l_ConfigListSaved); free(l_ConfigListSaved); l_ConfigListSaved = new_section; } else { curr_section = l_ConfigListSaved; while (curr_section->next != NULL && osal_insensitive_strcmp(SectionName, curr_section->next->name) > 0) curr_section = curr_section->next; if (curr_section->next == NULL || osal_insensitive_strcmp(SectionName, curr_section->next->name) < 0) { /* the saved section is new and goes after the curr_section */ new_section->next = curr_section->next; curr_section->next = new_section; } else { /* the saved section replaces curr_section->next */ config_section *old_section = curr_section->next; new_section->next = old_section->next; delete_section_vars(old_section); free(old_section); curr_section->next = new_section; } } /* write the saved config list out to a file */ return (write_configlist_file()); }
EXPORT int CALL ConfigHasUnsavedChanges(const char *SectionName) { config_section *input_section, *curr_section; config_var *active_var, *saved_var; /* check input conditions */ if (!l_ConfigInit) { DebugMessage(M64MSG_ERROR, "ConfigHasUnsavedChanges(): Core config not initialized!"); return 0; } /* if SectionName is NULL or blank, then check all sections */ if (SectionName == NULL || strlen(SectionName) < 1) { int iNumActiveSections = 0, iNumSavedSections = 0; /* first, search through all sections in Active list. Recursively call ourself and return 1 if changed */ curr_section = l_ConfigListActive; while (curr_section != NULL) { if (ConfigHasUnsavedChanges(curr_section->name)) return 1; curr_section = curr_section->next; iNumActiveSections++; } /* Next, count the number of Saved sections and see if the count matches */ curr_section = l_ConfigListSaved; while (curr_section != NULL) { curr_section = curr_section->next; iNumSavedSections++; } if (iNumActiveSections == iNumSavedSections) return 0; /* no changes */ else return 1; } /* walk through the Active section list, looking for a case-insensitive name match with input string */ input_section = l_ConfigListActive; while (input_section != NULL) { if (osal_insensitive_strcmp(SectionName, input_section->name) == 0) break; input_section = input_section->next; } if (input_section == NULL) { DebugMessage(M64MSG_ERROR, "ConfigHasUnsavedChanges(): section name '%s' not found!", SectionName); return 0; } /* walk through the Saved section list, looking for a case-insensitive name match */ curr_section = l_ConfigListSaved; while (curr_section != NULL) { if (osal_insensitive_strcmp(input_section->name, curr_section->name) == 0) break; curr_section = curr_section->next; } /* if this section isn't present in saved list, then it has been newly created */ if (curr_section == NULL) return 1; /* compare all of the variables in the two sections. They are expected to be in the same order */ active_var = input_section->first_var; saved_var = curr_section->first_var; while (active_var != NULL && saved_var != NULL) { if (strncmp(active_var->name, saved_var->name, 64) != 0) return 1; if (active_var->type != saved_var->type) return 1; switch(active_var->type) { case M64TYPE_INT: if (active_var->val_int != saved_var->val_int) return 1; break; case M64TYPE_FLOAT: if (active_var->val_float != saved_var->val_float) return 1; break; case M64TYPE_BOOL: if ((active_var->val_int != 0) != (saved_var->val_int != 0)) return 1; break; case M64TYPE_STRING: if (active_var->val_string == NULL) { DebugMessage(M64MSG_ERROR, "ConfigHasUnsavedChanges(): Variable '%s' NULL Active string pointer!", active_var->name); return 1; } if (saved_var->val_string == NULL) { DebugMessage(M64MSG_ERROR, "ConfigHasUnsavedChanges(): Variable '%s' NULL Saved string pointer!", active_var->name); return 1; } if (strcmp(active_var->val_string, saved_var->val_string) != 0) return 1; break; default: DebugMessage(M64MSG_ERROR, "ConfigHasUnsavedChanges(): Invalid variable '%s' type %i!", active_var->name, active_var->type); return 1; } if (active_var->comment != NULL && saved_var->comment != NULL && strcmp(active_var->comment, saved_var->comment) != 0) return 1; active_var = active_var->next; saved_var = saved_var->next; } /* any extra new variables on the end, or deleted variables? */ if (active_var != NULL || saved_var != NULL) return 1; /* exactly the same */ return 0; }
m64p_error ConfigInit(const char *ConfigDirOverride, const char *DataDirOverride) { m64p_error rval; const char *configpath = NULL; char *filepath; long filelen, pathlen; FILE *fPtr; char *configtext; config_section *current_section = NULL; char *line, *end, *lastcomment; if (l_ConfigInit) return M64ERR_ALREADY_INIT; l_ConfigInit = 1; /* if a data directory was specified, make a copy of it */ if (DataDirOverride != NULL) { l_DataDirOverride = (char *) malloc(strlen(DataDirOverride) + 1); if (l_DataDirOverride == NULL) return M64ERR_NO_MEMORY; strcpy(l_DataDirOverride, DataDirOverride); } /* if a config directory was specified, make a copy of it */ if (ConfigDirOverride != NULL) { l_ConfigDirOverride = (char *) malloc(strlen(ConfigDirOverride) + 1); if (l_ConfigDirOverride == NULL) return M64ERR_NO_MEMORY; strcpy(l_ConfigDirOverride, ConfigDirOverride); } /* get the full pathname to the config file and try to open it */ configpath = ConfigGetUserConfigPath(); if (configpath == NULL) return M64ERR_FILES; filepath = (char *) malloc(strlen(configpath) + 32); if (filepath == NULL) return M64ERR_NO_MEMORY; strcpy(filepath, configpath); pathlen = strlen(filepath); if (filepath[pathlen - 1] != OSAL_DIR_SEPARATOR) { filepath[pathlen] = OSAL_DIR_SEPARATOR; filepath[pathlen + 1] = 0; } strcat(filepath, MUPEN64PLUS_CFG_NAME); fPtr = fopen(filepath, "rb"); if (fPtr == NULL) { DebugMessage(M64MSG_INFO, "Couldn't open configuration file '%s'. Using defaults.", filepath); free(filepath); l_SaveConfigOnExit = 1; /* auto-save the config file so that the defaults will be saved to disk */ return M64ERR_SUCCESS; } free(filepath); /* read the entire config file */ fseek(fPtr, 0L, SEEK_END); filelen = ftell(fPtr); fseek(fPtr, 0L, SEEK_SET); configtext = (char *) malloc(filelen + 16); if (configtext == NULL) { fclose(fPtr); return M64ERR_NO_MEMORY; } if (fread(configtext, 1, filelen, fPtr) != filelen) { free(configtext); fclose(fPtr); return M64ERR_FILES; } fclose(fPtr); /* parse the file data */ current_section = NULL; line = configtext; end = configtext + filelen; lastcomment = NULL; *end = 0; while (line < end) { char *pivot, *varname, *varvalue; /* get the pointer to the next line, and null-terminate this line */ char *nextline = strchr(line, '\n'); if (nextline == NULL) nextline = end; *nextline++ = 0; /* strip the whitespace and handle comment */ strip_whitespace(line); if (strlen(line) < 1) { line = nextline; continue; } if (line[0] == '#') { line++; strip_whitespace(line); lastcomment = line; line = nextline; continue; } /* handle section definition line */ if (strlen(line) > 2 && line[0] == '[' && line[strlen(line)-1] == ']') { line++; line[strlen(line)-1] = 0; rval = ConfigOpenSection(line, (m64p_handle *) ¤t_section); if (rval != M64ERR_SUCCESS) { free(configtext); return rval; } lastcomment = NULL; line = nextline; continue; } /* handle variable definition */ pivot = strchr(line, '='); if (current_section == NULL || pivot == NULL) { line = nextline; continue; } varname = line; varvalue = pivot + 1; *pivot = 0; strip_whitespace(varname); strip_whitespace(varvalue); if (varvalue[0] == '"' && varvalue[strlen(varvalue)-1] == '"') { varvalue++; varvalue[strlen(varvalue)-1] = 0; ConfigSetDefaultString((m64p_handle) current_section, varname, varvalue, lastcomment); } else if (osal_insensitive_strcmp(varvalue, "false") == 0) { ConfigSetDefaultBool((m64p_handle) current_section, varname, 0, lastcomment); } else if (osal_insensitive_strcmp(varvalue, "true") == 0) { ConfigSetDefaultBool((m64p_handle) current_section, varname, 1, lastcomment); } else if (is_numeric(varvalue)) { int val_int = (int) strtol(varvalue, NULL, 10); float val_float = (float) strtod(varvalue, NULL); if ((val_float - val_int) != 0.0) ConfigSetDefaultFloat((m64p_handle) current_section, varname, val_float, lastcomment); else ConfigSetDefaultInt((m64p_handle) current_section, varname, val_int, lastcomment); } else { /* assume that it's a string */ ConfigSetDefaultString((m64p_handle) current_section, varname, varvalue, lastcomment); } lastcomment = NULL; line = nextline; } /* release memory used for config file text */ free(configtext); /* duplicate the entire config data list, to store a copy of the list which represents the state of the file on disk */ copy_configlist_active_to_saved(); return M64ERR_SUCCESS; }
static int SetConfigParameter(const char *ParamSpec) { char *ParsedString, *VarName, *VarValue=NULL; m64p_handle ConfigSection; m64p_type VarType; m64p_error rval; if (ParamSpec == NULL) { DebugMessage(M64MSG_ERROR, "ParamSpec is NULL in SetConfigParameter()"); return 1; } /* make a copy of the input string */ ParsedString = (char *) malloc(strlen(ParamSpec) + 1); if (ParsedString == NULL) { DebugMessage(M64MSG_ERROR, "SetConfigParameter() couldn't allocate memory for temporary string."); return 2; } strcpy(ParsedString, ParamSpec); /* parse it for the simple section[name]=value format */ VarName = strchr(ParsedString, '['); if (VarName != NULL) { *VarName++ = 0; VarValue = strchr(VarName, ']'); if (VarValue != NULL) { *VarValue++ = 0; } } if (VarName == NULL || VarValue == NULL || *VarValue != '=') { DebugMessage(M64MSG_ERROR, "invalid (param-spec) '%s'", ParamSpec); free(ParsedString); return 3; } VarValue++; /* then set the value */ rval = (*ConfigOpenSection)(ParsedString, &ConfigSection); if (rval != M64ERR_SUCCESS) { DebugMessage(M64MSG_ERROR, "SetConfigParameter failed to open config section '%s'", ParsedString); free(ParsedString); return 4; } if ((*ConfigGetParameterType)(ConfigSection, VarName, &VarType) == M64ERR_SUCCESS) { switch(VarType) { int ValueInt; float ValueFloat; case M64TYPE_INT: ValueInt = atoi(VarValue); ConfigSetParameter(ConfigSection, VarName, M64TYPE_INT, &ValueInt); break; case M64TYPE_FLOAT: ValueFloat = (float) atof(VarValue); ConfigSetParameter(ConfigSection, VarName, M64TYPE_FLOAT, &ValueFloat); break; case M64TYPE_BOOL: ValueInt = (int) (osal_insensitive_strcmp(VarValue, "true") == 0); ConfigSetParameter(ConfigSection, VarName, M64TYPE_BOOL, &ValueInt); break; case M64TYPE_STRING: ConfigSetParameter(ConfigSection, VarName, M64TYPE_STRING, VarValue); break; default: DebugMessage(M64MSG_ERROR, "invalid VarType in SetConfigParameter()"); return 5; } } else { ConfigSetParameter(ConfigSection, VarName, M64TYPE_STRING, VarValue); } free(ParsedString); return 0; }
m64p_error ConfigInit(const char *ConfigDirOverride, const char *DataDirOverride) { m64p_error rval; const char *configpath = NULL; char *filepath; long filelen; FILE *fPtr; char *configtext; config_section *current_section = NULL; char *line, *end, *lastcomment; if (l_ConfigInit) return M64ERR_ALREADY_INIT; l_ConfigInit = 1; /* if a data directory was specified, make a copy of it */ if (DataDirOverride != NULL) { l_DataDirOverride = strdup(DataDirOverride); if (l_DataDirOverride == NULL) return M64ERR_NO_MEMORY; /* TODO mupen64plus-ae specific hack */ strcpy(l_DataDirOverride, DataDirOverride); } /* if a config directory was specified, make a copy of it */ if (ConfigDirOverride != NULL) { l_ConfigDirOverride = strdup(ConfigDirOverride); if (l_ConfigDirOverride == NULL) return M64ERR_NO_MEMORY; } /* get the full pathname to the config file and try to open it */ configpath = ConfigGetUserConfigPath(); if (configpath == NULL) return M64ERR_FILES; filepath = combinepath(configpath, MUPEN64PLUS_CFG_NAME); if (filepath == NULL) return M64ERR_NO_MEMORY; fPtr = fopen(filepath, "rb"); if (fPtr == NULL) { DebugMessage(M64MSG_INFO, "Couldn't open configuration file '%s'. Using defaults.", filepath); free(filepath); l_SaveConfigOnExit = 1; /* auto-save the config file so that the defaults will be saved to disk */ return M64ERR_SUCCESS; } free(filepath); /* read the entire config file */ fseek(fPtr, 0L, SEEK_END); filelen = ftell(fPtr); fseek(fPtr, 0L, SEEK_SET); configtext = (char *) malloc(filelen + 1); if (configtext == NULL) { fclose(fPtr); return M64ERR_NO_MEMORY; } if (fread(configtext, 1, filelen, fPtr) != filelen) { free(configtext); fclose(fPtr); return M64ERR_FILES; } fclose(fPtr); /* parse the file data */ current_section = NULL; line = configtext; end = configtext + filelen; lastcomment = NULL; *end = 0; while (line < end) { ini_line l = ini_parse_line(&line); switch (l.type) { case INI_COMMENT: lastcomment = l.value; break; case INI_SECTION: rval = ConfigOpenSection(l.name, (m64p_handle *) ¤t_section); if (rval != M64ERR_SUCCESS) { free(configtext); return rval; } lastcomment = NULL; break; case INI_PROPERTY: if (l.value[0] == '"' && l.value[strlen(l.value)-1] == '"') { l.value++; l.value[strlen(l.value)-1] = 0; ConfigSetDefaultString((m64p_handle) current_section, l.name, l.value, lastcomment); } else if (osal_insensitive_strcmp(l.value, "false") == 0) { ConfigSetDefaultBool((m64p_handle) current_section, l.name, 0, lastcomment); } else if (osal_insensitive_strcmp(l.value, "true") == 0) { ConfigSetDefaultBool((m64p_handle) current_section, l.name, 1, lastcomment); } else if (is_numeric(l.value)) { int val_int = (int) strtol(l.value, NULL, 10); float val_float = (float) strtod(l.value, NULL); if ((val_float - val_int) != 0.0) ConfigSetDefaultFloat((m64p_handle) current_section, l.name, val_float, lastcomment); else ConfigSetDefaultInt((m64p_handle) current_section, l.name, val_int, lastcomment); } else { /* assume that it's a string */ ConfigSetDefaultString((m64p_handle) current_section, l.name, l.value, lastcomment); } lastcomment = NULL; break; default: break; } } /* release memory used for config file text */ free(configtext); /* duplicate the entire config data list, to store a copy of the list which represents the state of the file on disk */ copy_configlist_active_to_saved(); return M64ERR_SUCCESS; }