added setting Android log level for new logging functions
[rocksndiamonds.git] / src / libgame / misc.c
index c1450d4a7ab536e7751e7df69d92251b3f276f84..e3983f6d8e98b43b7e93414e6cf2800015f5c581 100644 (file)
@@ -251,6 +251,124 @@ void PrintLineWithPrefix(char *prefix, char *line_chars, int line_length)
 }
 
 
+// ----------------------------------------------------------------------------
+// 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 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
 // ----------------------------------------------------------------------------
@@ -876,7 +994,7 @@ boolean strSuffix(char *s, char *suffix)
          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)
@@ -932,6 +1050,7 @@ void GetOptions(int argc, char *argv[],
 
   options.execute_command = NULL;
   options.special_flags = NULL;
+  options.debug_mode = NULL;
 
   options.mytapes = FALSE;
   options.serveronly = FALSE;
@@ -1002,8 +1121,8 @@ void GetOptions(int argc, char *argv[],
        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++;
 
@@ -1020,7 +1139,7 @@ void GetOptions(int argc, char *argv[],
       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++;
     }
@@ -1029,7 +1148,7 @@ void GetOptions(int argc, char *argv[],
       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++;
     }
@@ -1038,7 +1157,7 @@ void GetOptions(int argc, char *argv[],
       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++;
     }
@@ -1047,7 +1166,7 @@ void GetOptions(int argc, char *argv[],
       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++;
     }
@@ -1066,6 +1185,10 @@ void GetOptions(int argc, char *argv[],
     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)
     {
@@ -1087,7 +1210,7 @@ void GetOptions(int argc, char *argv[],
       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++;
 
@@ -1756,7 +1879,7 @@ static void translate_keyname(Key *keysym, char **x11name, char **name, int mode
     }
 
     if (key == KSYM_UNDEFINED)
-      Error(ERR_WARN, "getKeyFromKeyName(): not completely implemented");
+      Warn("getKeyFromKeyName(): not completely implemented");
 
     *keysym = key;
   }
@@ -3275,53 +3398,53 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
 
     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);
@@ -3427,7 +3550,7 @@ static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
 
   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;
 
@@ -3453,7 +3576,7 @@ static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
 
     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);
 
@@ -3611,8 +3734,8 @@ void OpenLogFiles(void)
     {
       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