// (c) 1995-2014 by Artsoft Entertainment
// Holger Schemel
// info@artsoft.org
-// http://www.artsoft.org/
+// https://www.artsoft.org/
// ----------------------------------------------------------------------------
// misc.c
// ============================================================================
}
+// ----------------------------------------------------------------------------
+// generic logging functions
+// ----------------------------------------------------------------------------
+
+enum log_levels
+{
+ LOG_UNKNOWN = 0,
+ LOG_DEBUG,
+ LOG_INFO,
+ LOG_WARN,
+ LOG_ERROR,
+ LOG_FATAL
+};
+
+static char *log_tokens[] =
+{
+ "UNKNOWN",
+ "DEBUG",
+ "INFO",
+ "WARN",
+ "ERROR",
+ "FATAL"
+};
+
+static void printf_log_prefix(int log_level, char *mode)
+{
+ if (log_level < 0 || log_level > LOG_FATAL)
+ return;
+
+ char *log_token = log_tokens[log_level];
+
+ if (log_level == LOG_DEBUG)
+ printf_log_nonewline("[%s] [%s] ", log_token, mode);
+ else
+ printf_log_nonewline("[%s] ", log_token);
+}
+
+static void Log(int log_level, char *mode, char *format, va_list ap)
+{
+ if (log_level < 0 || log_level > LOG_FATAL)
+ return;
+
+#if defined(PLATFORM_ANDROID)
+ android_log_prio = (log_level == LOG_DEBUG ? ANDROID_LOG_DEBUG :
+ log_level == LOG_INFO ? ANDROID_LOG_INFO :
+ log_level == LOG_WARN ? ANDROID_LOG_WARN :
+ log_level == LOG_ERROR ? ANDROID_LOG_ERROR :
+ log_level == LOG_FATAL ? ANDROID_LOG_FATAL :
+ ANDROID_LOG_UNKNOWN);
+#endif
+
+ static boolean last_line_was_separator = FALSE;
+ char *log_token = log_tokens[log_level];
+
+ if (strEqual(format, "===") ||
+ strEqual(format, "---"))
+ {
+ static char *mode_last = NULL;
+ char line_char[2] = { format[0], '\0' };
+ int line_length = 80 - strlen(log_token) - 3;
+
+ if (log_level == LOG_DEBUG)
+ line_length -= strlen(mode) + 3;
+
+ if (last_line_was_separator && strEqual(mode, mode_last))
+ return;
+
+ printf_log_prefix(log_level, mode);
+ printf_log_line(line_char, line_length);
+
+ if (!strEqual(mode, mode_last))
+ setString(&mode_last, mode);
+
+ last_line_was_separator = TRUE;
+
+ return;
+ }
+
+ last_line_was_separator = FALSE;
+
+ printf_log_prefix(log_level, mode);
+
+ vprintf_log(format, ap);
+}
+
+void Debug(char *mode, char *format, ...)
+{
+ va_list ap;
+
+ if (!options.debug)
+ return;
+
+ // if optional debug mode specified, limit debug output accordingly
+ if (options.debug_mode != NULL &&
+ !strEqual(options.debug_mode, mode))
+ return;
+
+ va_start(ap, format);
+ Log(LOG_DEBUG, mode, format, ap);
+ va_end(ap);
+}
+
+void Info(char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ Log(LOG_INFO, NULL, format, ap);
+ va_end(ap);
+}
+
+void Warn(char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ Log(LOG_WARN, NULL, format, ap);
+ va_end(ap);
+}
+
+
// ----------------------------------------------------------------------------
// string functions
// ----------------------------------------------------------------------------
#if 0
#if DEBUG
- printf("::: %d: %d ms", *loop_var, delay);
if (skip_frames)
- printf(" -> SKIP %d FRAME(S) [%d ms]", skip_frames, skip_frames * delay);
- printf("\n");
+ Debug("internal:SkipUntilDelayReached",
+ "%d: %d ms -> SKIP %d FRAME(S) [%d ms]",
+ *loop_var, delay,
+ skip_frames, skip_frames * delay);
+ else
+ Debug("internal:SkipUntilDelayReached",
+ "%d: %d ms",
+ *loop_var, delay);
#endif
#endif
s == NULL && suffix != NULL ? FALSE :
s != NULL && suffix == NULL ? FALSE :
strlen(s) < strlen(suffix) ? FALSE :
- strncmp(&s[strlen(s) - strlen(suffix)], suffix, strlen(suffix)) == 0);
+ strcmp(&s[strlen(s) - strlen(suffix)], suffix) == 0);
}
boolean strPrefixLower(char *s, char *prefix)
options.execute_command = NULL;
options.special_flags = NULL;
+ options.debug_mode = NULL;
options.mytapes = FALSE;
options.serveronly = FALSE;
Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
// this should be extended to separate options for ro and rw data
- options.ro_base_directory = ro_base_path = option_arg;
- options.rw_base_directory = rw_base_path = option_arg;
+ options.ro_base_directory = ro_base_path = getStringCopy(option_arg);
+ options.rw_base_directory = rw_base_path = getStringCopy(option_arg);
if (option_arg == next_option)
options_left++;
if (option_arg == NULL)
Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
- options.level_directory = option_arg;
+ options.level_directory = getStringCopy(option_arg);
if (option_arg == next_option)
options_left++;
}
if (option_arg == NULL)
Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
- options.graphics_directory = option_arg;
+ options.graphics_directory = getStringCopy(option_arg);
if (option_arg == next_option)
options_left++;
}
if (option_arg == NULL)
Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
- options.sounds_directory = option_arg;
+ options.sounds_directory = getStringCopy(option_arg);
if (option_arg == next_option)
options_left++;
}
if (option_arg == NULL)
Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
- options.music_directory = option_arg;
+ options.music_directory = getStringCopy(option_arg);
if (option_arg == next_option)
options_left++;
}
else if (strncmp(option, "-debug", option_len) == 0)
{
options.debug = TRUE;
+
+ // optionally, debug output can be limited to a specific debug mode
+ if (option_arg != next_option)
+ options.debug_mode = getStringCopy(option_arg);
}
else if (strncmp(option, "-verbose", option_len) == 0)
{
if (option_arg == NULL)
Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
- options.execute_command = option_arg;
+ options.execute_command = getStringCopy(option_arg);
if (option_arg == next_option)
options_left++;
{
int i;
- for(i = 0; i < bytes; i++)
+ for (i = 0; i < bytes; i++)
fputc(buffer[i], file);
}
}
if (key == KSYM_UNDEFINED)
- Error(ERR_WARN, "getKeyFromKeyName(): not completely implemented");
+ Warn("getKeyFromKeyName(): not completely implemented");
*keysym = key;
}
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>.
-
-static boolean string_has_parameter(char *s, char *s_contained)
-{
- char *substring;
-
- if (s == NULL || s_contained == NULL)
- return FALSE;
-
- if (strlen(s_contained) > strlen(s))
- return FALSE;
-
- if (strncmp(s, s_contained, strlen(s_contained)) == 0)
- {
- char next_char = s[strlen(s_contained)];
-
- // check if next character is delimiter or whitespace
- return (next_char == ',' || next_char == '\0' ||
- next_char == ' ' || next_char == '\t' ? TRUE : FALSE);
- }
-
- // check if string contains another parameter string after a comma
- substring = strchr(s, ',');
- if (substring == NULL) // string does not contain a comma
- return FALSE;
-
- // advance string pointer to next character after the comma
- substring++;
-
- // skip potential whitespaces after the comma
- while (*substring == ' ' || *substring == '\t')
- substring++;
-
- return string_has_parameter(substring, s_contained);
-}
-
-static int get_anim_parameter_value(char *s)
-{
- char *pattern_1 = "click:anim_";
- char *pattern_2 = ".part_";
- char *matching_char = NULL;
- char *s_ptr = s;
- int result = ANIM_EVENT_NONE;
-
- matching_char = strstr(s_ptr, pattern_1);
- if (matching_char == NULL)
- return ANIM_EVENT_NONE;
-
- s_ptr = matching_char + strlen(pattern_1);
-
- // check for main animation number ("anim_X" or "anim_XX")
- if (*s_ptr >= '0' && *s_ptr <= '9')
- {
- int gic_anim_nr = (*s_ptr++ - '0');
-
- if (*s_ptr >= '0' && *s_ptr <= '9')
- gic_anim_nr = 10 * gic_anim_nr + (*s_ptr++ - '0');
-
- if (gic_anim_nr < 1 || gic_anim_nr > MAX_GLOBAL_ANIMS)
- return ANIM_EVENT_NONE;
-
- result |= gic_anim_nr << ANIM_EVENT_ANIM_BIT;
- }
- else
- {
- // invalid main animation number specified
-
- return ANIM_EVENT_NONE;
- }
-
- // check for animation part number ("part_X" or "part_XX") (optional)
- if (strPrefix(s_ptr, pattern_2))
- {
- s_ptr += strlen(pattern_2);
-
- if (*s_ptr >= '0' && *s_ptr <= '9')
- {
- int gic_part_nr = (*s_ptr++ - '0');
-
- if (*s_ptr >= '0' && *s_ptr <= '9')
- gic_part_nr = 10 * gic_part_nr + (*s_ptr++ - '0');
-
- if (gic_part_nr < 1 || gic_part_nr > MAX_GLOBAL_ANIM_PARTS)
- return ANIM_EVENT_NONE;
-
- result |= gic_part_nr << ANIM_EVENT_PART_BIT;
- }
- else
- {
- // invalid animation part number specified
-
- return ANIM_EVENT_NONE;
- }
- }
-
- // discard result if next character is neither delimiter nor whitespace
- if (!(*s_ptr == ',' || *s_ptr == '\0' ||
- *s_ptr == ' ' || *s_ptr == '\t'))
- return ANIM_EVENT_NONE;
-
- return result;
-}
-
-static int get_anim_action_parameter_value(char *token)
-{
- int result = getImageIDFromToken(token);
-
- if (result == -1)
- {
- char *gfx_token = getStringCat2("gfx.", token);
-
- result = getImageIDFromToken(gfx_token);
-
- checked_free(gfx_token);
- }
-
- if (result == -1)
- {
- Key key = getKeyFromX11KeyName(token);
-
- if (key != KSYM_UNDEFINED)
- result = -(int)key;
- }
-
- if (result == -1)
- result = ANIM_EVENT_ACTION_NONE;
-
- return result;
-}
-
-int get_parameter_value(char *value_raw, char *suffix, int type)
-{
- char *value = getStringToLower(value_raw);
- int result = 0; // probably a save default value
-
- if (strEqual(suffix, ".direction"))
- {
- result = (strEqual(value, "left") ? MV_LEFT :
- strEqual(value, "right") ? MV_RIGHT :
- 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 :
- strEqual(value, "last") ? POS_LAST : POS_UNDEFINED);
- }
- else if (strEqual(suffix, ".align"))
- {
- result = (strEqual(value, "left") ? ALIGN_LEFT :
- strEqual(value, "right") ? ALIGN_RIGHT :
- strEqual(value, "center") ? ALIGN_CENTER :
- strEqual(value, "middle") ? ALIGN_CENTER : ALIGN_DEFAULT);
- }
- else if (strEqual(suffix, ".valign"))
- {
- result = (strEqual(value, "top") ? VALIGN_TOP :
- strEqual(value, "bottom") ? VALIGN_BOTTOM :
- strEqual(value, "middle") ? VALIGN_MIDDLE :
- strEqual(value, "center") ? VALIGN_MIDDLE : VALIGN_DEFAULT);
- }
- else if (strEqual(suffix, ".anim_mode"))
- {
- result = (string_has_parameter(value, "none") ? ANIM_NONE :
- string_has_parameter(value, "loop") ? ANIM_LOOP :
- string_has_parameter(value, "linear") ? ANIM_LINEAR :
- string_has_parameter(value, "pingpong") ? ANIM_PINGPONG :
- string_has_parameter(value, "pingpong2") ? ANIM_PINGPONG2 :
- string_has_parameter(value, "random") ? ANIM_RANDOM :
- string_has_parameter(value, "ce_value") ? ANIM_CE_VALUE :
- string_has_parameter(value, "ce_score") ? ANIM_CE_SCORE :
- string_has_parameter(value, "ce_delay") ? ANIM_CE_DELAY :
- 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;
-
- if (string_has_parameter(value, "opaque_player"))
- result |= ANIM_OPAQUE_PLAYER;
-
- if (string_has_parameter(value, "static_panel"))
- result |= ANIM_STATIC_PANEL;
- }
- else if (strEqual(suffix, ".init_event") ||
- strEqual(suffix, ".anim_event"))
- {
- result = ANIM_EVENT_DEFAULT;
-
- if (string_has_parameter(value, "any"))
- result |= ANIM_EVENT_ANY;
-
- if (string_has_parameter(value, "click"))
- result |= ANIM_EVENT_SELF;
-
- // add optional "click:anim_X" or "click:anim_X.part_X" parameter
- result |= get_anim_parameter_value(value);
- }
- else if (strEqual(suffix, ".init_event_action") ||
- strEqual(suffix, ".anim_event_action"))
- {
- result = get_anim_action_parameter_value(value_raw);
- }
- else if (strEqual(suffix, ".class"))
- {
- result = (strEqual(value, ARG_UNDEFINED) ? ARG_UNDEFINED_VALUE :
- get_hash_from_key(value));
- }
- else if (strEqual(suffix, ".style"))
- {
- result = STYLE_DEFAULT;
-
- if (string_has_parameter(value, "accurate_borders"))
- result |= STYLE_ACCURATE_BORDERS;
-
- if (string_has_parameter(value, "inner_corners"))
- result |= STYLE_INNER_CORNERS;
-
- if (string_has_parameter(value, "reverse"))
- result |= STYLE_REVERSE;
-
- if (string_has_parameter(value, "passthrough_clicks"))
- result |= STYLE_PASSTHROUGH;
-
- if (string_has_parameter(value, "multiple_actions"))
- result |= STYLE_MULTIPLE_ACTIONS;
- }
- else if (strEqual(suffix, ".fade_mode"))
- {
- result = (string_has_parameter(value, "none") ? FADE_MODE_NONE :
- 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")
- {
- result = gfx.get_font_from_token_function(value);
- }
- else // generic parameter of type integer or boolean
- {
- result = (strEqual(value, ARG_UNDEFINED) ? ARG_UNDEFINED_VALUE :
- type == TYPE_INTEGER ? get_integer_from_string(value) :
- type == TYPE_BOOLEAN ? get_boolean_from_string(value) :
- ARG_UNDEFINED_VALUE);
- }
-
- free(value);
-
- return result;
-}
-
static void FreeCustomArtworkList(struct ArtworkListInfo *,
struct ListNodeInfo ***, int *);
if (options.debug && dynamic_tokens_found)
{
- Error(ERR_INFO_LINE, "-");
- Error(ERR_INFO, "dynamic token(s) found in config file:");
- Error(ERR_INFO, "- config file: '%s'", filename);
+ Debug("config", "---");
+ Debug("config", "dynamic token(s) found in config file:");
+ Debug("config", "- config file: '%s'", filename);
for (list = setup_file_list; list != NULL; list = list->next)
{
char *value = getHashEntry(extra_file_hash, list->token);
if (value != NULL && strEqual(value, known_token_value))
- Error(ERR_INFO, "- dynamic token: '%s'", list->token);
+ Debug("config", "- dynamic token: '%s'", list->token);
}
- Error(ERR_INFO_LINE, "-");
+ Debug("config", "---");
}
if (unknown_tokens_found)
{
- Error(ERR_INFO_LINE, "-");
- Error(ERR_INFO, "warning: unknown token(s) found in config file:");
- Error(ERR_INFO, "- config file: '%s'", filename);
+ Warn("---");
+ Warn("unknown token(s) found in config file:");
+ Warn("- config file: '%s'", filename);
for (list = setup_file_list; list != NULL; list = list->next)
{
char *value = getHashEntry(extra_file_hash, list->token);
if (value != NULL && !strEqual(value, known_token_value))
- Error(ERR_INFO, "- dynamic token: '%s'", list->token);
+ Warn("- dynamic token: '%s'", list->token);
}
- Error(ERR_INFO_LINE, "-");
+ Warn("---");
}
if (undefined_values_found)
{
- Error(ERR_INFO_LINE, "-");
- Error(ERR_INFO, "warning: undefined values found in config file:");
- Error(ERR_INFO, "- config file: '%s'", filename);
+ Warn("---");
+ Warn("undefined values found in config file:");
+ Warn("- config file: '%s'", filename);
for (list = setup_file_list; list != NULL; list = list->next)
{
char *value = getHashEntry(empty_file_hash, list->token);
if (value != NULL)
- Error(ERR_INFO, "- undefined value for token: '%s'", list->token);
+ Warn("- undefined value for token: '%s'", list->token);
}
- Error(ERR_INFO_LINE, "-");
+ Warn("---");
}
freeSetupFileList(setup_file_list);
if (filename == NULL)
{
- Error(ERR_WARN, "cannot find artwork file '%s'", basename);
+ Warn("cannot find artwork file '%s'", basename);
basename = file_list_entry->default_filename;
file_list_entry->fallback_to_default = TRUE;
- Error(ERR_WARN, "trying default artwork file '%s'", basename);
+ Warn("trying default artwork file '%s'", basename);
filename = getCustomArtworkFilename(basename, artwork_info->type);
{
program.log_file[i] = program.log_file_default[i]; // reset to default
- Error(ERR_WARN, "cannot open file '%s' for writing: %s",
- program.log_filename[i], strerror(errno));
+ Warn("cannot open file '%s' for writing: %s",
+ program.log_filename[i], strerror(errno));
}
// output should be unbuffered so it is not truncated in a crash