static void sleep_milliseconds(unsigned int milliseconds_delay)
{
- boolean do_busy_waiting = (milliseconds_delay < 5 ? TRUE : FALSE);
-
- if (do_busy_waiting)
- {
- /* we want to wait only a few ms -- if we assume that we have a
- kernel timer resolution of 10 ms, we would wait far too long;
- therefore it's better to do a short interval of busy waiting
- to get our sleeping time more accurate */
-
- unsigned int base_counter = Counter(), actual_counter = Counter();
-
- while (actual_counter < base_counter + milliseconds_delay &&
- actual_counter >= base_counter)
- actual_counter = Counter();
- }
- else
- {
- SDL_Delay(milliseconds_delay);
- }
+ SDL_Delay(milliseconds_delay);
}
void Delay(unsigned int delay) /* Sleep specified number of milliseconds */
sleep_milliseconds(delay);
}
-boolean FrameReached(unsigned int *frame_counter_var,
- unsigned int frame_delay)
+boolean DelayReachedExt(unsigned int *counter_var, unsigned int delay,
+ unsigned int actual_counter)
{
- unsigned int actual_frame_counter = FrameCounter;
-
- if (actual_frame_counter >= *frame_counter_var &&
- actual_frame_counter < *frame_counter_var + frame_delay)
+ if (actual_counter >= *counter_var &&
+ actual_counter < *counter_var + delay)
return FALSE;
- *frame_counter_var = actual_frame_counter;
+ *counter_var = actual_counter;
return TRUE;
}
-boolean DelayReached(unsigned int *counter_var,
- unsigned int delay)
+boolean FrameReached(unsigned int *frame_counter_var, unsigned int frame_delay)
{
- unsigned int actual_counter = Counter();
+ return DelayReachedExt(frame_counter_var, frame_delay, FrameCounter);
+}
- if (actual_counter >= *counter_var &&
- actual_counter < *counter_var + delay)
- return FALSE;
+boolean DelayReached(unsigned int *counter_var, unsigned int delay)
+{
+ return DelayReachedExt(counter_var, delay, Counter());
+}
- *counter_var = actual_counter;
+void ResetDelayCounterExt(unsigned int *counter_var,
+ unsigned int actual_counter)
+{
+ DelayReachedExt(counter_var, 0, actual_counter);
+}
- return TRUE;
+void ResetFrameCounter(unsigned int *frame_counter_var)
+{
+ FrameReached(frame_counter_var, 0);
+}
+
+void ResetDelayCounter(unsigned int *counter_var)
+{
+ DelayReached(counter_var, 0);
}
int WaitUntilDelayReached(unsigned int *counter_var, unsigned int delay)
return getStringCat3WithSeparator(path1, path2, path3, STRING_PATH_SEPARATOR);
}
-char *getImg2(char *path1, char *path2)
+static char *getPngOrPcxIfNotExists(char *filename)
{
- char *filename = getPath2(path1, path2);
-
- if (!fileExists(filename) && strSuffix(path2, ".png"))
- {
- // backward compatibility: if PNG file not found, check for PCX file
- char *path2pcx = getStringCopy(path2);
-
- strcpy(&path2pcx[strlen(path2pcx) - 3], "pcx");
+ // switch from PNG to PCX file and vice versa, if file does not exist
+ // (backwards compatibility with PCX files used in previous versions)
- free(filename);
-
- filename = getPath2(path1, path2pcx);
-
- free(path2pcx);
- }
+ if (!fileExists(filename) && strSuffix(filename, ".png"))
+ strcpy(&filename[strlen(filename) - 3], "pcx");
+ else if (!fileExists(filename) && strSuffix(filename, ".pcx"))
+ strcpy(&filename[strlen(filename) - 3], "png");
return filename;
}
-char *getImg3(char *path1, char *path2, char *path3)
+char *getImg2(char *path1, char *path2)
{
- char *filename = getPath3(path1, path2, path3);
-
- if (!fileExists(filename) && strSuffix(path3, ".png"))
- {
- // backward compatibility: if PNG file not found, check for PCX file
- char *path3pcx = getStringCopy(path3);
-
- strcpy(&path3pcx[strlen(path3pcx) - 3], "pcx");
-
- free(filename);
-
- filename = getPath3(path1, path2, path3pcx);
-
- free(path3pcx);
- }
+ return getPngOrPcxIfNotExists(getPath2(path1, path2));
+}
- return filename;
+char *getImg3(char *path1, char *path2, char *path3)
+{
+ return getPngOrPcxIfNotExists(getPath3(path1, path2, path3));
}
char *getStringCopy(const char *s)
/* command line option handling functions */
/* ------------------------------------------------------------------------- */
-void GetOptions(char *argv[],
+void GetOptions(int argc, char *argv[],
void (*print_usage_function)(void),
void (*print_version_function)(void))
{
char *ro_base_path = RO_BASE_PATH;
char *rw_base_path = RW_BASE_PATH;
- char **options_left = &argv[1];
+ char **argvplus = checked_calloc((argc + 1) * sizeof(char **));
+ char **options_left = &argvplus[1];
+
+ /* replace original "argv" with null-terminated array of string pointers */
+ while (argc--)
+ argvplus[argc] = argv[argc];
/* if the program is configured to start from current directory (default),
determine program package directory from program binary (some versions
rw_base_path = getProgramMainDataPath();
/* initialize global program options */
- options.display_name = NULL;
options.server_host = NULL;
options.server_port = 0;
exit(0);
}
- else if (strncmp(option, "-display", option_len) == 0)
- {
- if (option_arg == NULL)
- Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
-
- options.display_name = option_arg;
- if (option_arg == next_option)
- options_left++;
- }
else if (strncmp(option, "-basepath", option_len) == 0)
{
if (option_arg == NULL)
/* when doing batch processing, always enable verbose mode (warnings) */
options.verbose = TRUE;
}
+#if defined(PLATFORM_MACOSX)
+ else if (strPrefix(option, "-psn"))
+ {
+ /* ignore process serial number when launched via GUI on Mac OS X */
+ }
+#endif
else if (*option == '-')
{
Error(ERR_EXIT_HELP, "unrecognized option '%s'", option_str);
if (strEqual((*node_first)->key, key))
{
- checked_free((*node_first)->key);
+ // after first recursion, (*node_first)->prev->next == *node_first,
+ // so *node_first would be overwritten with (*node_first)->next
+ // => use a copy of *node_first (and later of (*node_first)->next)
+ ListNode *node = *node_first;
+ ListNode *node_next = node->next;
+
+ checked_free(node->key);
if (destructor_function)
- destructor_function((*node_first)->content);
+ destructor_function(node->content);
+
+ if (node->prev)
+ node->prev->next = node->next;
- if ((*node_first)->next)
- (*node_first)->next->prev = (*node_first)->prev;
+ if (node->next)
+ node->next->prev = node->prev;
- checked_free(*node_first);
+ checked_free(node);
- *node_first = (*node_first)->next;
+ // after removing node, set list pointer to next valid list node
+ // (this is important if the first node of the list was deleted)
+ *node_first = node_next;
}
else
+ {
deleteNodeFromList(&(*node_first)->next, key, destructor_function);
+ }
}
ListNode *getNodeFromKey(ListNode *node_first, char *key)
return getStringCat2(map_token_prefix[i][1], &token[len_token_prefix]);
}
+ // change tokens containing ".gfx" by moving the "gfx" part to the very left
+ char *gfx_substring = ".gfx";
+ char *gfx_prefix = "gfx.";
+ if (strstr(token, gfx_substring) != NULL)
+ {
+ char *token_prefix = getStringCopy(token);
+ char *token_gfx_pos = strstr(token_prefix, gfx_substring);
+ char *token_suffix = &token_gfx_pos[strlen(gfx_substring)];
+ char *mapped_token;
+
+ // cut off token string at ".gfx" substring position
+ *token_gfx_pos = '\0';
+
+ // put together prefix "gfx." and token prefix and suffix without ".gfx"
+ mapped_token = getStringCat3(gfx_prefix, token_prefix, token_suffix);
+
+ free(token_prefix);
+
+ return mapped_token;
+ }
+
return NULL;
}
+char *get_special_base_token(struct ArtworkListInfo *artwork_info, char *token)
+{
+ /* !!! make this dynamically configurable (init.c:InitArtworkConfig) !!! */
+ static struct ConfigTypeInfo prefix_list[] =
+ {
+ { "global.anim_1" },
+ { "global.anim_2" },
+ { "global.anim_3" },
+ { "global.anim_4" },
+ { "global.anim_5" },
+ { "global.anim_6" },
+ { "global.anim_7" },
+ { "global.anim_8" },
+
+ { NULL }
+ };
+ struct ConfigTypeInfo *suffix_list = artwork_info->suffix_list;
+ boolean prefix_found = FALSE;
+ int len_suffix = 0;
+ int i;
+
+ /* search for prefix to check if base token has to be created */
+ for (i = 0; prefix_list[i].token != NULL; i++)
+ if (strPrefix(token, prefix_list[i].token))
+ prefix_found = TRUE;
+
+ if (!prefix_found)
+ return NULL;
+
+ /* search for suffix (parameter) to determine base token length */
+ for (i = 0; suffix_list[i].token != NULL; i++)
+ if (strSuffix(token, suffix_list[i].token))
+ len_suffix = strlen(suffix_list[i].token);
+
+ return getStringCopyN(token, strlen(token) - len_suffix);
+}
+
/* This function checks if a string <s> of the format "string1, string2, ..."
exactly contains a string <s_contained>. */
strEqual(value, "up") ? MV_UP :
strEqual(value, "down") ? MV_DOWN : MV_NONE);
}
+ else if (strEqual(suffix, ".position"))
+ {
+ result = (strEqual(value, "left") ? POS_LEFT :
+ strEqual(value, "right") ? POS_RIGHT :
+ strEqual(value, "top") ? POS_TOP :
+ strEqual(value, "upper") ? POS_UPPER :
+ strEqual(value, "middle") ? POS_MIDDLE :
+ strEqual(value, "lower") ? POS_LOWER :
+ strEqual(value, "bottom") ? POS_BOTTOM :
+ strEqual(value, "any") ? POS_ANY : POS_UNDEFINED);
+ }
else if (strEqual(suffix, ".align"))
{
result = (strEqual(value, "left") ? ALIGN_LEFT :
string_has_parameter(value, "horizontal") ? ANIM_HORIZONTAL :
string_has_parameter(value, "vertical") ? ANIM_VERTICAL :
string_has_parameter(value, "centered") ? ANIM_CENTERED :
+ string_has_parameter(value, "all") ? ANIM_ALL :
ANIM_DEFAULT);
+ if (string_has_parameter(value, "once"))
+ result |= ANIM_ONCE;
+
if (string_has_parameter(value, "reverse"))
result |= ANIM_REVERSE;
}
else if (strEqual(suffix, ".class"))
{
- result = get_hash_from_key(value);
+ result = (strEqual(value, ARG_UNDEFINED) ? ARG_UNDEFINED_VALUE :
+ get_hash_from_key(value));
}
else if (strEqual(suffix, ".style"))
{
string_has_parameter(value, "fade") ? FADE_MODE_FADE :
string_has_parameter(value, "crossfade") ? FADE_MODE_CROSSFADE :
string_has_parameter(value, "melt") ? FADE_MODE_MELT :
+ string_has_parameter(value, "curtain") ? FADE_MODE_CURTAIN :
FADE_MODE_DEFAULT);
}
else if (strPrefix(suffix, ".font")) /* (may also be ".font_xyz") */
return result;
}
-struct ScreenModeInfo *get_screen_mode_from_string(char *screen_mode_string)
-{
- static struct ScreenModeInfo screen_mode;
- char *screen_mode_string_x = strchr(screen_mode_string, 'x');
- char *screen_mode_string_copy;
- char *screen_mode_string_pos_w;
- char *screen_mode_string_pos_h;
-
- if (screen_mode_string_x == NULL) /* invalid screen mode format */
- return NULL;
-
- screen_mode_string_copy = getStringCopy(screen_mode_string);
-
- screen_mode_string_pos_w = screen_mode_string_copy;
- screen_mode_string_pos_h = strchr(screen_mode_string_copy, 'x');
- *screen_mode_string_pos_h++ = '\0';
-
- screen_mode.width = atoi(screen_mode_string_pos_w);
- screen_mode.height = atoi(screen_mode_string_pos_h);
-
- return &screen_mode;
-}
-
-void get_aspect_ratio_from_screen_mode(struct ScreenModeInfo *screen_mode,
- int *x, int *y)
-{
- float aspect_ratio = (float)screen_mode->width / (float)screen_mode->height;
- float aspect_ratio_new;
- int i = 1;
-
- do
- {
- *x = i * aspect_ratio + 0.000001;
- *y = i;
-
- aspect_ratio_new = (float)*x / (float)*y;
-
- i++;
- }
- while (aspect_ratio_new != aspect_ratio && *y < screen_mode->height);
-}
-
static void FreeCustomArtworkList(struct ArtworkListInfo *,
struct ListNodeInfo ***, int *);
int num_ext2_suffixes = artwork_info->num_ext2_suffixes;
int num_ext3_suffixes = artwork_info->num_ext3_suffixes;
int num_ignore_tokens = artwork_info->num_ignore_tokens;
- SetupFileHash *setup_file_hash, *valid_file_hash;
+ SetupFileHash *setup_file_hash, *valid_file_hash, *valid_file_hash_tmp;
SetupFileHash *extra_file_hash, *empty_file_hash;
char *known_token_value = KNOWN_TOKEN_VALUE;
+ char *base_token_value = UNDEFINED_FILENAME;
int i, j, k, l;
if (filename == NULL)
/* at this point, we do not need the setup file hash anymore -- free it */
freeSetupFileHash(setup_file_hash);
- /* map deprecated to current tokens (using prefix match and replace) */
+ /* prevent changing hash while iterating over it by using a temporary copy */
+ valid_file_hash_tmp = newSetupFileHash();
BEGIN_HASH_ITERATION(valid_file_hash, itr)
+ {
+ setHashEntry(valid_file_hash_tmp,
+ HASH_ITERATION_TOKEN(itr),
+ HASH_ITERATION_VALUE(itr));
+ }
+ END_HASH_ITERATION(valid_file_hash, itr)
+
+ /* (iterate over same temporary hash, as modifications are independent) */
+
+ /* map deprecated to current tokens (using prefix match and replace) */
+ BEGIN_HASH_ITERATION(valid_file_hash_tmp, itr)
{
char *token = HASH_ITERATION_TOKEN(itr);
char *mapped_token = get_mapped_token(token);
free(mapped_token);
}
}
- END_HASH_ITERATION(valid_file_hash, itr)
+ END_HASH_ITERATION(valid_file_hash_tmp, itr)
+
+ /* add special base tokens (using prefix match and replace) */
+ BEGIN_HASH_ITERATION(valid_file_hash_tmp, itr)
+ {
+ char *token = HASH_ITERATION_TOKEN(itr);
+ char *base_token = get_special_base_token(artwork_info, token);
+
+ if (base_token != NULL)
+ {
+ /* add base token only if it does not already exist */
+ if (getHashEntry(valid_file_hash, base_token) == NULL)
+ setHashEntry(valid_file_hash, base_token, base_token_value);
+
+ free(base_token);
+ }
+ }
+ END_HASH_ITERATION(valid_file_hash_tmp, itr)
+
+ /* free temporary hash used for iteration */
+ freeSetupFileHash(valid_file_hash_tmp);
/* read parameters for all known config file tokens */
for (i = 0; i < num_file_list_entries; i++)
boolean unknown_tokens_found = FALSE;
boolean undefined_values_found = (hashtable_count(empty_file_hash) != 0);
- if ((setup_file_list = loadSetupFileList(filename)) == NULL)
- Error(ERR_EXIT, "loadSetupFileHash works, but loadSetupFileList fails");
+ /* list may be NULL for empty artwork config files */
+ setup_file_list = loadSetupFileList(filename);
BEGIN_HASH_ITERATION(extra_file_hash, itr)
{