- new->value = checked_malloc(strlen(value) + 1);
- strcpy(new->value, value);
-
- new->next = NULL;
-
- return new;
-}
-
-static char *getTokenValue(struct SetupFileList *setup_file_list,
- char *token)
-{
- if (!setup_file_list)
- return NULL;
-
- if (strcmp(setup_file_list->token, token) == 0)
- return setup_file_list->value;
- else
- return getTokenValue(setup_file_list->next, token);
-}
-
-static void setTokenValue(struct SetupFileList *setup_file_list,
- char *token, char *value)
-{
- if (!setup_file_list)
- return;
-
- if (strcmp(setup_file_list->token, token) == 0)
- {
- free(setup_file_list->value);
- setup_file_list->value = checked_malloc(strlen(value) + 1);
- strcpy(setup_file_list->value, value);
- }
- else if (setup_file_list->next == NULL)
- setup_file_list->next = newSetupFileList(token, value);
- else
- setTokenValue(setup_file_list->next, token, value);
-}
-
-#ifdef DEBUG
-static void printSetupFileList(struct SetupFileList *setup_file_list)
-{
- if (!setup_file_list)
- return;
-
- printf("token: '%s'\n", setup_file_list->token);
- printf("value: '%s'\n", setup_file_list->value);
-
- printSetupFileList(setup_file_list->next);
-}
-#endif
-
-static struct SetupFileList *loadSetupFileList(char *filename)
-{
- int line_len;
- char line[MAX_LINE_LEN];
- char *token, *value, *line_ptr;
- struct SetupFileList *setup_file_list = newSetupFileList("", "");
- struct SetupFileList *first_valid_list_entry;
-
- FILE *file;
-
- if (!(file = fopen(filename, MODE_READ)))
- {
- Error(ERR_WARN, "cannot open configuration file '%s'", filename);
- return NULL;
- }
-
- while(!feof(file))
- {
- /* read next line of input file */
- if (!fgets(line, MAX_LINE_LEN, file))
- break;
-
- /* cut trailing comment or whitespace from input line */
- for (line_ptr = line; *line_ptr; line_ptr++)
- {
- if (*line_ptr == '#' || *line_ptr == '\n' || *line_ptr == '\r')
- {
- *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;
-
- line_len = strlen(line);
-
- /* cut leading whitespaces from token */
- for (token = line; *token; token++)
- if (*token != ' ' && *token != '\t')
- break;
-
- /* find end of token */
- for (line_ptr = token; *line_ptr; line_ptr++)
- {
- if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':')
- {
- *line_ptr = '\0';
- break;
- }
- }
-
- if (line_ptr < line + line_len)
- value = line_ptr + 1;
- else
- value = "\0";
-
- /* cut leading whitespaces from value */
- for (; *value; value++)
- if (*value != ' ' && *value != '\t')
- break;
-
- if (*token && *value)
- setTokenValue(setup_file_list, token, value);
- }
-
- fclose(file);
-
- first_valid_list_entry = setup_file_list->next;
-
- /* free empty list header */
- setup_file_list->next = NULL;
- freeSetupFileList(setup_file_list);
-
- if (first_valid_list_entry == NULL)
- Error(ERR_WARN, "configuration file '%s' is empty", filename);
-
- return first_valid_list_entry;
-}
-
-static void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list,
- char *identifier)
-{
- if (!setup_file_list)
- return;
-
- if (strcmp(setup_file_list->token, TOKEN_STR_FILE_IDENTIFIER) == 0)
- {
- if (strcmp(setup_file_list->value, identifier) != 0)
- {
- Error(ERR_WARN, "configuration file has wrong version");
- return;
- }
- else
- return;
- }
-
- if (setup_file_list->next)
- checkSetupFileListIdentifier(setup_file_list->next, identifier);
- else
- {
- Error(ERR_WARN, "configuration file has no version information");
- return;
- }
-}
-
-static void setLevelDirInfoToDefaults(struct LevelDirInfo *ldi)
-{
- ldi->filename = NULL;
- ldi->fullpath = NULL;
- ldi->basepath = NULL;
- ldi->name = getStringCopy(ANONYMOUS_NAME);
- ldi->name_short = NULL;
- ldi->name_sorting = NULL;
- ldi->author = getStringCopy(ANONYMOUS_NAME);
- ldi->imported_from = NULL;
- ldi->levels = 0;
- ldi->first_level = 0;
- ldi->last_level = 0;
- ldi->sort_priority = LEVELCLASS_UNDEFINED; /* default: least priority */
- ldi->level_group = FALSE;
- ldi->parent_link = FALSE;
- ldi->user_defined = FALSE;
- ldi->readonly = TRUE;
- ldi->color = 0;
- ldi->class_desc = NULL;
- ldi->handicap_level = 0;
- ldi->cl_first = -1;
- ldi->cl_cursor = -1;
-
- ldi->node_parent = NULL;
- ldi->node_group = NULL;
- ldi->next = NULL;
-}
-
-static void setLevelDirInfoToDefaultsFromParent(struct LevelDirInfo *ldi,
- struct LevelDirInfo *parent)
-{
- if (parent == NULL)
- {
- setLevelDirInfoToDefaults(ldi);
- return;
- }
-
- /* first copy all values from the parent structure ... */
- *ldi = *parent;
-
- /* ... then set all fields to default that cannot be inherited from parent.
- This is especially important for all those fields that can be set from
- the 'levelinfo.conf' config file, because the function 'setSetupInfo()'
- calls 'free()' for all already set token values which requires that no
- other structure's pointer may point to them!
- */
-
- ldi->filename = NULL;
- ldi->fullpath = NULL;
- ldi->basepath = NULL;
- ldi->name = getStringCopy(ANONYMOUS_NAME);
- ldi->name_short = NULL;
- ldi->name_sorting = NULL;
- ldi->author = getStringCopy(parent->author);
- ldi->imported_from = getStringCopy(parent->imported_from);
-
- ldi->level_group = FALSE;
- ldi->parent_link = FALSE;
-
- ldi->node_parent = parent;
- ldi->node_group = NULL;
- ldi->next = NULL;
-}
-
-static void setSetupInfoToDefaults(struct SetupInfo *si)
-{
- int i;
-
- si->player_name = getStringCopy(getLoginName());
-
- si->sound = TRUE;
- si->sound_loops = TRUE;
- si->sound_music = TRUE;
- si->sound_simple = TRUE;
- si->toons = TRUE;
- si->double_buffering = TRUE;
- si->direct_draw = !si->double_buffering;
- si->scroll_delay = TRUE;
- si->soft_scrolling = TRUE;
- si->fading = FALSE;
- si->autorecord = TRUE;
- si->quick_doors = FALSE;
- si->team_mode = FALSE;
- si->handicap = TRUE;
- si->time_limit = TRUE;
- si->fullscreen = FALSE;
-
- for (i=0; i<MAX_PLAYERS; i++)
- {
- si->input[i].use_joystick = FALSE;
- si->input[i].joy.device_name = getStringCopy(joystick_device_name[i]);
- si->input[i].joy.xleft = JOYSTICK_XLEFT;
- si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
- si->input[i].joy.xright = JOYSTICK_XRIGHT;
- si->input[i].joy.yupper = JOYSTICK_YUPPER;
- si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
- si->input[i].joy.ylower = JOYSTICK_YLOWER;
- si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0);
- si->input[i].joy.bomb = (i == 0 ? JOY_BUTTON_2 : 0);
- si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED);
- si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
- si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED);
- si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED);
- si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED);
- si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KSYM_UNDEFINED);
- }
-}
-
-static void setSetupInfo(int token_nr, char *token_value)
-{
- int token_type = token_info[token_nr].type;
- void *setup_value = token_info[token_nr].value;
-
- if (token_value == NULL)
- return;
-
- /* set setup field to corresponding token value */
- switch (token_type)
- {
- case TYPE_BOOLEAN:
- case TYPE_SWITCH:
- *(boolean *)setup_value = get_string_boolean_value(token_value);
- break;
-
- case TYPE_KEY:
- *(Key *)setup_value = getKeyFromX11KeyName(token_value);
- break;
-
- case TYPE_INTEGER:
- *(int *)setup_value = get_string_integer_value(token_value);
- break;
-
- case TYPE_STRING:
- if (*(char **)setup_value != NULL)
- free(*(char **)setup_value);
- *(char **)setup_value = getStringCopy(token_value);
- break;
-
- default:
- break;
- }
-}
-
-static void decodeSetupFileList(struct SetupFileList *setup_file_list)
-{
- int i, pnr;
-
- if (!setup_file_list)
- return;
-
- /* handle global setup values */
- si = setup;
- for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++)
- setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text));
- setup = si;
-
- /* handle player specific setup values */
- for (pnr=0; pnr<MAX_PLAYERS; pnr++)
- {
- char prefix[30];
-
- sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
-
- sii = setup.input[pnr];
- for (i=FIRST_PLAYER_SETUP_TOKEN; i<=LAST_PLAYER_SETUP_TOKEN; i++)
- {
- char full_token[100];
-
- sprintf(full_token, "%s%s", prefix, token_info[i].text);
- setSetupInfo(i, getTokenValue(setup_file_list, full_token));
- }
- setup.input[pnr] = sii;
- }
-}
-
-static int compareLevelDirInfoEntries(const void *object1, const void *object2)
-{
- const struct LevelDirInfo *entry1 = *((struct LevelDirInfo **)object1);
- const struct LevelDirInfo *entry2 = *((struct LevelDirInfo **)object2);
- int compare_result;
-
- if (entry1->parent_link || entry2->parent_link)
- compare_result = (entry1->parent_link ? -1 : +1);
- else if (entry1->sort_priority == entry2->sort_priority)
- {
- char *name1 = getStringToLower(entry1->name_sorting);
- char *name2 = getStringToLower(entry2->name_sorting);
-
- compare_result = strcmp(name1, name2);
-
- free(name1);
- free(name2);
- }
- else if (LEVELSORTING(entry1) == LEVELSORTING(entry2))
- compare_result = entry1->sort_priority - entry2->sort_priority;
- else
- compare_result = LEVELSORTING(entry1) - LEVELSORTING(entry2);
-
- return compare_result;
-}
-
-static void createParentLevelDirNode(struct LevelDirInfo *node_parent)
-{
- struct LevelDirInfo *leveldir_new = newLevelDirInfo();
-
- setLevelDirInfoToDefaults(leveldir_new);
-
- leveldir_new->node_parent = node_parent;
- leveldir_new->parent_link = TRUE;
-
- leveldir_new->name = ".. (parent directory)";
- leveldir_new->name_short = getStringCopy(leveldir_new->name);
- leveldir_new->name_sorting = getStringCopy(leveldir_new->name);
-
- leveldir_new->filename = "..";
- leveldir_new->fullpath = getStringCopy(node_parent->fullpath);
-
- leveldir_new->sort_priority = node_parent->sort_priority;
- leveldir_new->class_desc = getLevelClassDescription(leveldir_new);
-
- pushLevelDirInfo(&node_parent->node_group, leveldir_new);
-}
-
-static void LoadLevelInfoFromLevelDir(struct LevelDirInfo **node_first,
- struct LevelDirInfo *node_parent,
- char *level_directory)
-{
- DIR *dir;
- struct dirent *dir_entry;
- boolean valid_entry_found = FALSE;
-
- if ((dir = opendir(level_directory)) == NULL)
- {
- Error(ERR_WARN, "cannot read level directory '%s'", level_directory);
- return;
- }
-
- while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */
- {
- struct SetupFileList *setup_file_list = NULL;
- struct stat file_status;
- char *directory_name = dir_entry->d_name;
- char *directory_path = getPath2(level_directory, directory_name);
- char *filename = NULL;
-
- /* skip entries for current and parent directory */
- if (strcmp(directory_name, ".") == 0 ||
- strcmp(directory_name, "..") == 0)
- {
- free(directory_path);
- continue;
- }
-
- /* find out if directory entry is itself a directory */
- if (stat(directory_path, &file_status) != 0 || /* cannot stat file */
- (file_status.st_mode & S_IFMT) != S_IFDIR) /* not a directory */
- {
- free(directory_path);
- continue;
- }
-
- filename = getPath2(directory_path, LEVELINFO_FILENAME);
- setup_file_list = loadSetupFileList(filename);
-
- if (setup_file_list)
- {
- struct LevelDirInfo *leveldir_new = newLevelDirInfo();
- int i;
-
- checkSetupFileListIdentifier(setup_file_list, LEVELINFO_COOKIE);
- setLevelDirInfoToDefaultsFromParent(leveldir_new, node_parent);
-
- /* set all structure fields according to the token/value pairs */
- ldi = *leveldir_new;
- for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++)
- setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text));
- *leveldir_new = ldi;
-
- DrawInitText(leveldir_new->name, 150, FC_YELLOW);
-
- if (leveldir_new->name_short == NULL)
- leveldir_new->name_short = getStringCopy(leveldir_new->name);
-
- if (leveldir_new->name_sorting == NULL)
- leveldir_new->name_sorting = getStringCopy(leveldir_new->name);
-
- leveldir_new->filename = getStringCopy(directory_name);
-
- if (node_parent == NULL) /* top level group */
- {
- leveldir_new->basepath = level_directory;
- leveldir_new->fullpath = leveldir_new->filename;
- }
- else /* sub level group */
- {
- leveldir_new->basepath = node_parent->basepath;
- leveldir_new->fullpath = getPath2(node_parent->fullpath,
- directory_name);
- }
-
- if (leveldir_new->levels < 1)
- leveldir_new->levels = 1;
-
- leveldir_new->last_level =
- leveldir_new->first_level + leveldir_new->levels - 1;
-
- leveldir_new->user_defined =
- (leveldir_new->basepath == options.level_directory ? FALSE : TRUE);
-
- leveldir_new->color = LEVELCOLOR(leveldir_new);
- leveldir_new->class_desc = getLevelClassDescription(leveldir_new);
-
- leveldir_new->handicap_level = /* set handicap to default value */
- (leveldir_new->user_defined ?
- leveldir_new->last_level :
- leveldir_new->first_level);
-
- pushLevelDirInfo(node_first, leveldir_new);
-
- freeSetupFileList(setup_file_list);
- valid_entry_found = TRUE;
-
- if (leveldir_new->level_group)
- {
- /* create node to link back to current level directory */
- createParentLevelDirNode(leveldir_new);
-
- /* step into sub-directory and look for more level series */
- LoadLevelInfoFromLevelDir(&leveldir_new->node_group,
- leveldir_new, directory_path);
- }
- }
- else
- Error(ERR_WARN, "ignoring level directory '%s'", directory_path);
-
- free(directory_path);
- free(filename);
- }
-
- closedir(dir);
-
- if (!valid_entry_found)
- Error(ERR_WARN, "cannot find any valid level series in directory '%s'",
- level_directory);
-}
-
-void LoadLevelInfo()
-{
- InitUserLevelDirectory(getLoginName());
-
- DrawInitText("Loading level series:", 120, FC_GREEN);
-
- LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory);
- LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir(""));
-
- leveldir_current = getFirstValidLevelSeries(leveldir_first);
-
- if (leveldir_first == NULL)
- Error(ERR_EXIT, "cannot find any valid level series in any directory");
-
- sortLevelDirInfo(&leveldir_first, compareLevelDirInfoEntries);
-
-#if 0
- dumpLevelDirInfo(leveldir_first, 0);
-#endif
-}
-
-static void SaveUserLevelInfo()
-{
- char *filename;
- FILE *file;
- int i;
-
- filename = getPath2(getUserLevelDir(getLoginName()), LEVELINFO_FILENAME);
-
- if (!(file = fopen(filename, MODE_WRITE)))
- {
- Error(ERR_WARN, "cannot write level info file '%s'", filename);
- free(filename);
- return;
- }
-
- /* always start with reliable default values */
- setLevelDirInfoToDefaults(&ldi);
-
- ldi.name = getLoginName();
- ldi.author = getRealName();
- ldi.levels = 100;
- ldi.first_level = 1;
- ldi.sort_priority = LEVELCLASS_USER_START;
- ldi.readonly = FALSE;
-
- fprintf(file, "%s\n\n",
- getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, LEVELINFO_COOKIE));
-
- for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++)
- if (i != LEVELINFO_TOKEN_NAME_SHORT &&
- i != LEVELINFO_TOKEN_NAME_SORTING &&
- i != LEVELINFO_TOKEN_IMPORTED_FROM)
- fprintf(file, "%s\n", getSetupLine("", i));
-
- fclose(file);
- free(filename);
-
- SetFilePermissions_Setup(filename);
-}
-
-void LoadSetup()
-{
- char *filename;
- struct SetupFileList *setup_file_list = NULL;
-
- /* always start with reliable default values */
- setSetupInfoToDefaults(&setup);
-
- filename = getPath2(getSetupDir(), SETUP_FILENAME);
-
- setup_file_list = loadSetupFileList(filename);