- include_count++;
- }
- else
- {
- Error(ERR_WARN, "ignoring already processed file '%s'", value);
- }
- }
- else
- {
- if (is_hash)
- {
-#if CHECK_TOKEN__WARN_IF_ALREADY_EXISTS_IN_HASH
- char *old_value =
- getHashEntry((SetupFileHash *)setup_file_data, token);
-
- if (old_value != NULL)
- {
- if (!token_already_exists_warning)
- {
- Error(ERR_INFO_LINE, "-");
- Error(ERR_WARN, "duplicate token(s) found in config file:");
- Error(ERR_INFO, "- config file: '%s'", filename);
-
- token_already_exists_warning = TRUE;
- }
-
- Error(ERR_INFO, "- token: '%s' (in line %d)", token, line_nr);
- Error(ERR_INFO, " old value: '%s'", old_value);
- Error(ERR_INFO, " new value: '%s'", value);
- }
-#endif
-
- setHashEntry((SetupFileHash *)setup_file_data, token, value);
- }
- else
- {
- insert_ptr = addListEntry((SetupFileList *)insert_ptr, token, value);
- }
-
- token_count++;
- }
- }
- }
-
- fclose(file);
-
-#if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING
- if (token_value_separator_warning)
- Error(ERR_INFO_LINE, "-");
-#endif
-
-#if CHECK_TOKEN__WARN_IF_ALREADY_EXISTS_IN_HASH
- if (token_already_exists_warning)
- Error(ERR_INFO_LINE, "-");
-#endif
-
- if (token_count == 0 && include_count == 0)
- Error(ERR_WARN, "configuration file '%s' is empty", filename);
-
- if (top_recursion_level)
- freeSetupFileHash(include_filename_hash);
-
- return TRUE;
-}
-
-#endif
-
-#else
-
-static boolean loadSetupFileData(void *setup_file_data, char *filename,
- boolean top_recursion_level, boolean is_hash)
-{
- static SetupFileHash *include_filename_hash = NULL;
- char line[MAX_LINE_LEN], line_raw[MAX_LINE_LEN], previous_line[MAX_LINE_LEN];
- char *token, *value, *line_ptr;
- void *insert_ptr = NULL;
- boolean read_continued_line = FALSE;
- FILE *file;
- int line_nr = 0;
- int token_count = 0;
-
-#if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING
- token_value_separator_warning = FALSE;
-#endif
-
- if (!(file = fopen(filename, MODE_READ)))
- {
- Error(ERR_WARN, "cannot open configuration file '%s'", filename);
-
- return FALSE;
- }
-
- /* use "insert pointer" to store list end for constant insertion complexity */
- if (!is_hash)
- insert_ptr = setup_file_data;
-
- /* on top invocation, create hash to mark included files (to prevent loops) */
- if (top_recursion_level)
- include_filename_hash = newSetupFileHash();
-
- /* mark this file as already included (to prevent including it again) */
- setHashEntry(include_filename_hash, getBaseNamePtr(filename), "true");
-
- while (!feof(file))
- {
- /* read next line of input file */
- if (!fgets(line, MAX_LINE_LEN, file))
- break;
-
- /* check if line was completely read and is terminated by line break */
- if (strlen(line) > 0 && line[strlen(line) - 1] == '\n')
- line_nr++;
-
- /* cut trailing line break (this can be newline and/or carriage return) */
- for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--)
- if ((*line_ptr == '\n' || *line_ptr == '\r') && *(line_ptr + 1) == '\0')
- *line_ptr = '\0';
-
- /* copy raw input line for later use (mainly debugging output) */
- strcpy(line_raw, line);
-
- if (read_continued_line)
- {
- /* cut leading whitespaces from input line */
- for (line_ptr = line; *line_ptr; line_ptr++)
- if (*line_ptr != ' ' && *line_ptr != '\t')
- break;
-
- /* append new line to existing line, if there is enough space */
- if (strlen(previous_line) + strlen(line_ptr) < MAX_LINE_LEN)
- strcat(previous_line, line_ptr);
-
- strcpy(line, previous_line); /* copy storage buffer to line */
-
- read_continued_line = FALSE;
- }
-
- /* if the last character is '\', continue at next line */
- if (strlen(line) > 0 && line[strlen(line) - 1] == '\\')
- {
- line[strlen(line) - 1] = '\0'; /* cut off trailing backslash */
- strcpy(previous_line, line); /* copy line to storage buffer */
-
- read_continued_line = TRUE;
-
- continue;
- }
-
- /* cut trailing comment from input line */
- for (line_ptr = line; *line_ptr; line_ptr++)
- {
- if (*line_ptr == '#')
- {
- *line_ptr = '\0';
- break;
- }
- }
-
- /* cut trailing whitespaces from input line */
- for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--)
- if ((*line_ptr == ' ' || *line_ptr == '\t') && *(line_ptr + 1) == '\0')
- *line_ptr = '\0';
-
- /* ignore empty lines */
- if (*line == '\0')
- continue;
-
- /* cut leading whitespaces from token */
- for (token = line; *token; token++)
- if (*token != ' ' && *token != '\t')
- break;
-
- /* start with empty value as reliable default */
- value = "";
-
- token_value_separator_found = FALSE;
-
- /* find end of token to determine start of value */
- for (line_ptr = token; *line_ptr; line_ptr++)
- {
-#if 1
- /* first look for an explicit token/value separator, like ':' or '=' */
- if (*line_ptr == ':' || *line_ptr == '=')
-#else
- if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':')
-#endif
- {
- *line_ptr = '\0'; /* terminate token string */
- value = line_ptr + 1; /* set beginning of value */
-
- token_value_separator_found = TRUE;
-
- break;
- }
- }
-
-#if ALLOW_TOKEN_VALUE_SEPARATOR_BEING_WHITESPACE
- /* fallback: if no token/value separator found, also allow whitespaces */
- if (!token_value_separator_found)
- {
- for (line_ptr = token; *line_ptr; line_ptr++)
- {
- if (*line_ptr == ' ' || *line_ptr == '\t')
- {
- *line_ptr = '\0'; /* terminate token string */
- value = line_ptr + 1; /* set beginning of value */
-
- token_value_separator_found = TRUE;
-
- break;
- }
- }
-
-#if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING
- if (token_value_separator_found)
- {
- if (!token_value_separator_warning)
- {
- Error(ERR_INFO_LINE, "-");
- Error(ERR_WARN, "missing token/value separator(s) in config file:");
- Error(ERR_INFO, "- config file: '%s'", filename);
-
- token_value_separator_warning = TRUE;
- }
-
- Error(ERR_INFO, "- line %d: '%s'", line_nr, line_raw);
- }
-#endif
- }
-#endif
-
- /* cut trailing whitespaces from token */
- for (line_ptr = &token[strlen(token)]; line_ptr >= token; line_ptr--)
- if ((*line_ptr == ' ' || *line_ptr == '\t') && *(line_ptr + 1) == '\0')
- *line_ptr = '\0';
-
- /* cut leading whitespaces from value */
- for (; *value; value++)
- if (*value != ' ' && *value != '\t')
- break;
-
-#if 0
- if (*value == '\0')
- value = "true"; /* treat tokens without value as "true" */
-#endif
-
- if (*token)
- {
- if (strEqual(token, "include"))
- {
- if (getHashEntry(include_filename_hash, value) == NULL)
- {
- char *basepath = getBasePath(filename);
- char *basename = getBaseName(value);
- char *filename_include = getPath2(basepath, basename);
-
-#if 0
- Error(ERR_INFO, "[including file '%s']", filename_include);
-#endif
-
- loadSetupFileData(setup_file_data, filename_include, FALSE, is_hash);
-
- free(basepath);
- free(basename);
- free(filename_include);
- }
- else
- {
- Error(ERR_WARN, "ignoring already processed file '%s'", value);
- }
- }
- else
- {
- if (is_hash)
- setHashEntry((SetupFileHash *)setup_file_data, token, value);
- else
- insert_ptr = addListEntry((SetupFileList *)insert_ptr, token, value);
-
- token_count++;
- }
- }
- }
-
- fclose(file);
-
-#if CHECK_TOKEN_VALUE_SEPARATOR__WARN_IF_MISSING
- if (token_value_separator_warning)
- Error(ERR_INFO_LINE, "-");
-#endif
-
- if (token_count == 0)
- Error(ERR_WARN, "configuration file '%s' is empty", filename);
-
- if (top_recursion_level)
- freeSetupFileHash(include_filename_hash);
-
- return TRUE;
-}
-#endif
-
-void saveSetupFileHash(SetupFileHash *hash, char *filename)
-{
- FILE *file;
-
- if (!(file = fopen(filename, MODE_WRITE)))
- {
- Error(ERR_WARN, "cannot write configuration file '%s'", filename);
-
- return;
- }
-
- BEGIN_HASH_ITERATION(hash, itr)
- {
- fprintf(file, "%s\n", getFormattedSetupEntry(HASH_ITERATION_TOKEN(itr),
- HASH_ITERATION_VALUE(itr)));
- }
- END_HASH_ITERATION(hash, itr)
-
- fclose(file);
-}
-
-SetupFileList *loadSetupFileList(char *filename)
-{
- SetupFileList *setup_file_list = newSetupFileList("", "");
- SetupFileList *first_valid_list_entry;
-
- if (!loadSetupFileData(setup_file_list, filename, TRUE, FALSE))
- {
- freeSetupFileList(setup_file_list);
-
- return NULL;
- }
-
- first_valid_list_entry = setup_file_list->next;
-
- /* free empty list header */
- setup_file_list->next = NULL;
- freeSetupFileList(setup_file_list);
-
- return first_valid_list_entry;
-}
-
-SetupFileHash *loadSetupFileHash(char *filename)
-{
- SetupFileHash *setup_file_hash = newSetupFileHash();
-
- if (!loadSetupFileData(setup_file_hash, filename, TRUE, TRUE))
- {
- freeSetupFileHash(setup_file_hash);
-
- return NULL;
- }
-
- return setup_file_hash;
-}
-
-void checkSetupFileHashIdentifier(SetupFileHash *setup_file_hash,
- char *filename, char *identifier)
-{
- char *value = getHashEntry(setup_file_hash, TOKEN_STR_FILE_IDENTIFIER);
-
- if (value == NULL)
- Error(ERR_WARN, "config file '%s' has no file identifier", filename);
- else if (!checkCookieString(value, identifier))
- Error(ERR_WARN, "config file '%s' has wrong file identifier", filename);
-}
-
-
-/* ========================================================================= */
-/* setup file stuff */
-/* ========================================================================= */
-
-#define TOKEN_STR_LAST_LEVEL_SERIES "last_level_series"
-#define TOKEN_STR_LAST_PLAYED_LEVEL "last_played_level"
-#define TOKEN_STR_HANDICAP_LEVEL "handicap_level"
-
-/* level directory info */
-#define LEVELINFO_TOKEN_IDENTIFIER 0
-#define LEVELINFO_TOKEN_NAME 1
-#define LEVELINFO_TOKEN_NAME_SORTING 2
-#define LEVELINFO_TOKEN_AUTHOR 3
-#define LEVELINFO_TOKEN_YEAR 4
-#define LEVELINFO_TOKEN_IMPORTED_FROM 5
-#define LEVELINFO_TOKEN_IMPORTED_BY 6
-#define LEVELINFO_TOKEN_TESTED_BY 7
-#define LEVELINFO_TOKEN_LEVELS 8
-#define LEVELINFO_TOKEN_FIRST_LEVEL 9
-#define LEVELINFO_TOKEN_SORT_PRIORITY 10
-#define LEVELINFO_TOKEN_LATEST_ENGINE 11
-#define LEVELINFO_TOKEN_LEVEL_GROUP 12
-#define LEVELINFO_TOKEN_READONLY 13
-#define LEVELINFO_TOKEN_GRAPHICS_SET_ECS 14
-#define LEVELINFO_TOKEN_GRAPHICS_SET_AGA 15
-#define LEVELINFO_TOKEN_GRAPHICS_SET 16
-#define LEVELINFO_TOKEN_SOUNDS_SET 17
-#define LEVELINFO_TOKEN_MUSIC_SET 18
-#define LEVELINFO_TOKEN_FILENAME 19
-#define LEVELINFO_TOKEN_FILETYPE 20
-#define LEVELINFO_TOKEN_SPECIAL_FLAGS 21
-#define LEVELINFO_TOKEN_HANDICAP 22
-#define LEVELINFO_TOKEN_SKIP_LEVELS 23
-
-#define NUM_LEVELINFO_TOKENS 24
-
-static LevelDirTree ldi;