rnd-20100325-1-src
[rocksndiamonds.git] / src / libgame / misc.c
index cfee3b2de339d5a5eb4029605b6fd8074e0e6fd1..35b9c5abc357cdb36b8c874a4b138d3dc1c0e6fd 100644 (file)
@@ -14,6 +14,7 @@
 #include <time.h>
 #include <sys/time.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <stdarg.h>
 #include <ctype.h>
 #include <string.h>
@@ -337,13 +338,26 @@ unsigned int init_random_number(int nr, long seed)
 {
   if (seed == NEW_RANDOMIZE)
   {
-#if defined(TARGET_SDL)
-    seed = (long)SDL_GetTicks();
-#else
+    /* default random seed */
+    seed = (long)time(NULL);                   // seconds since the epoch
+
+#if !defined(PLATFORM_WIN32)
+    /* add some more randomness */
     struct timeval current_time;
 
     gettimeofday(&current_time, NULL);
-    seed = (long)current_time.tv_usec;
+
+    seed += (long)current_time.tv_usec;                // microseconds since the epoch
+#endif
+
+#if defined(TARGET_SDL)
+    /* add some more randomness */
+    seed += (long)SDL_GetTicks();              // milliseconds since SDL init
+#endif
+
+#if 1
+    /* add some more randomness */
+    seed += GetSimpleRandom(1000000);
 #endif
   }
 
@@ -455,6 +469,16 @@ char *getRealName()
   return real_name;
 }
 
+time_t getFileTimestampEpochSeconds(char *filename)
+{
+  struct stat file_status;
+
+  if (stat(filename, &file_status) != 0)       /* cannot stat file */
+    return 0;
+
+  return file_status.st_mtime;
+}
+
 
 /* ------------------------------------------------------------------------- */
 /* path manipulation functions                                               */
@@ -607,7 +631,7 @@ boolean strEqualN(char *s1, char *s2, int n)
          strncmp(s1, s2, n) == 0);
 }
 
-boolean strEqualPrefix(char *s, char *prefix)
+boolean strPrefix(char *s, char *prefix)
 {
   return (s == NULL && prefix == NULL ? TRUE  :
          s == NULL && prefix != NULL ? FALSE :
@@ -615,7 +639,7 @@ boolean strEqualPrefix(char *s, char *prefix)
          strncmp(s, prefix, strlen(prefix)) == 0);
 }
 
-boolean strEqualSuffix(char *s, char *suffix)
+boolean strSuffix(char *s, char *suffix)
 {
   return (s == NULL && suffix == NULL ? TRUE  :
          s == NULL && suffix != NULL ? FALSE :
@@ -624,6 +648,26 @@ boolean strEqualSuffix(char *s, char *suffix)
          strncmp(&s[strlen(s) - strlen(suffix)], suffix, strlen(suffix)) == 0);
 }
 
+boolean strPrefixLower(char *s, char *prefix)
+{
+  char *s_lower = getStringToLower(s);
+  boolean match = strPrefix(s_lower, prefix);
+
+  free(s_lower);
+
+  return match;
+}
+
+boolean strSuffixLower(char *s, char *suffix)
+{
+  char *s_lower = getStringToLower(s);
+  boolean match = strSuffix(s_lower, suffix);
+
+  free(s_lower);
+
+  return match;
+}
+
 
 /* ------------------------------------------------------------------------- */
 /* command line option handling functions                                    */
@@ -652,6 +696,7 @@ void GetOptions(char *argv[], void (*print_usage_function)(void))
   options.display_name = NULL;
   options.server_host = NULL;
   options.server_port = 0;
+
   options.ro_base_directory = ro_base_path;
   options.rw_base_directory = rw_base_path;
   options.level_directory    = getPath2(ro_base_path, LEVELS_DIRECTORY);
@@ -659,11 +704,15 @@ void GetOptions(char *argv[], void (*print_usage_function)(void))
   options.sounds_directory   = getPath2(ro_base_path, SOUNDS_DIRECTORY);
   options.music_directory    = getPath2(ro_base_path, MUSIC_DIRECTORY);
   options.docs_directory     = getPath2(ro_base_path, DOCS_DIRECTORY);
+
   options.execute_command = NULL;
+  options.special_flags = NULL;
+
   options.serveronly = FALSE;
   options.network = FALSE;
   options.verbose = FALSE;
   options.debug = FALSE;
+  options.debug_x11_sync = FALSE;
 
 #if !defined(PLATFORM_UNIX)
   if (*options_left == NULL)   /* no options given -- enable verbose mode */
@@ -687,7 +736,7 @@ void GetOptions(char *argv[], void (*print_usage_function)(void))
     if (strEqual(option, "--"))                        /* stop scanning arguments */
       break;
 
-    if (strncmp(option, "--", 2) == 0)         /* treat '--' like '-' */
+    if (strPrefix(option, "--"))               /* treat '--' like '-' */
       option++;
 
     option_arg = strchr(option, '=');
@@ -789,6 +838,29 @@ void GetOptions(char *argv[], void (*print_usage_function)(void))
     {
       options.debug = TRUE;
     }
+    else if (strncmp(option, "-debug-x11-sync", option_len) == 0)
+    {
+      options.debug_x11_sync = TRUE;
+    }
+    else if (strPrefix(option, "-D"))
+    {
+#if 1
+      options.special_flags = getStringCopy(&option[2]);
+#else
+      char *flags_string = &option[2];
+      unsigned long flags_value;
+
+      if (*flags_string == '\0')
+       Error(ERR_EXIT_HELP, "empty flag ignored");
+
+      flags_value = get_special_flags_function(flags_string);
+
+      if (flags_value == 0)
+       Error(ERR_EXIT_HELP, "unknown flag '%s'", flags_string);
+
+      options.special_flags |= flags_value;
+#endif
+    }
     else if (strncmp(option, "-execute", option_len) == 0)
     {
       if (option_arg == NULL)
@@ -950,6 +1022,19 @@ void checked_free(void *ptr)
     free(ptr);
 }
 
+void clear_mem(void *ptr, unsigned long size)
+{
+#if defined(PLATFORM_WIN32)
+  /* for unknown reason, memset() sometimes crashes when compiled with MinGW */
+  char *cptr = (char *)ptr;
+
+  while (size--)
+    *cptr++ = 0;
+#else
+  memset(ptr, 0, size);
+#endif
+}
+
 
 /* ------------------------------------------------------------------------- */
 /* various helper functions                                                  */
@@ -1378,7 +1463,7 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode)
     Key key = KSYM_UNDEFINED;
     char *name_ptr = *x11name;
 
-    if (strncmp(name_ptr, "XK_", 3) == 0 && strlen(name_ptr) == 4)
+    if (strPrefix(name_ptr, "XK_") && strlen(name_ptr) == 4)
     {
       char c = name_ptr[3];
 
@@ -1389,14 +1474,14 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode)
       else if (c >= '0' && c <= '9')
        key = KSYM_0 + (Key)(c - '0');
     }
-    else if (strncmp(name_ptr, "XK_KP_", 6) == 0 && strlen(name_ptr) == 7)
+    else if (strPrefix(name_ptr, "XK_KP_") && strlen(name_ptr) == 7)
     {
       char c = name_ptr[6];
 
       if (c >= '0' && c <= '9')
        key = KSYM_KP_0 + (Key)(c - '0');
     }
-    else if (strncmp(name_ptr, "XK_F", 4) == 0 && strlen(name_ptr) <= 6)
+    else if (strPrefix(name_ptr, "XK_F") && strlen(name_ptr) <= 6)
     {
       char c1 = name_ptr[4];
       char c2 = name_ptr[5];
@@ -1409,7 +1494,7 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode)
       if (d >= 1 && d <= KSYM_NUM_FKEYS)
        key = KSYM_F1 + (Key)(d - 1);
     }
-    else if (strncmp(name_ptr, "XK_", 3) == 0)
+    else if (strPrefix(name_ptr, "XK_"))
     {
       i = 0;
 
@@ -1423,7 +1508,7 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode)
       }
       while (translate_key[++i].x11name);
     }
-    else if (strncmp(name_ptr, "0x", 2) == 0)
+    else if (strPrefix(name_ptr, "0x"))
     {
       unsigned long value = 0;
 
@@ -1582,6 +1667,24 @@ boolean get_boolean_from_string(char *s)
   return result;
 }
 
+int get_switch3_from_string(char *s)
+{
+  char *s_lower = getStringToLower(s);
+  int result = FALSE;
+
+  if (strEqual(s_lower, "true") ||
+      strEqual(s_lower, "yes") ||
+      strEqual(s_lower, "on") ||
+      get_integer_from_string(s) == 1)
+    result = TRUE;
+  else if (strEqual(s_lower, "auto"))
+    result = AUTO;
+
+  free(s_lower);
+
+  return result;
+}
+
 
 /* ------------------------------------------------------------------------- */
 /* functions for generic lists                                               */
@@ -1866,6 +1969,20 @@ int get_parameter_value(char *value_raw, char *suffix, int type)
     if (string_has_parameter(value, "static_panel"))
       result |= ANIM_STATIC_PANEL;
   }
+  else if (strEqual(suffix, ".class"))
+  {
+    result = 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, "with_inner_corners"))
+      result |= STYLE_WITH_INNER_CORNERS;
+  }
   else if (strEqual(suffix, ".fade_mode"))
   {
     result = (string_has_parameter(value, "none")      ? FADE_MODE_NONE :
@@ -1875,7 +1992,7 @@ int get_parameter_value(char *value_raw, char *suffix, int type)
              FADE_MODE_DEFAULT);
   }
 #if 1
-  else if (strEqualPrefix(suffix, ".font"))    /* (may also be ".font_xyz") */
+  else if (strPrefix(suffix, ".font"))         /* (may also be ".font_xyz") */
 #else
   else if (strEqualN(suffix, ".font", 5))      /* (may also be ".font_xyz") */
 #endif
@@ -1979,6 +2096,7 @@ struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list,
 
       file_list[i].redefined = FALSE;
       file_list[i].fallback_to_default = FALSE;
+      file_list[i].default_is_cloned = FALSE;
     }
   }
 
@@ -2035,6 +2153,9 @@ struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list,
       printf("::: '%s' => '%s'\n", config_list[i].token, config_list[i].value);
 #endif
     }
+
+    if (strSuffix(config_list[i].token, ".clone_from"))
+      file_list[list_pos].default_is_cloned = TRUE;
   }
 
   num_file_list_entries_found = list_pos + 1;
@@ -2143,6 +2264,7 @@ static void add_dynamic_file_list_entry(struct FileInfo **list,
 
   new_list_entry->redefined = FALSE;
   new_list_entry->fallback_to_default = FALSE;
+  new_list_entry->default_is_cloned = FALSE;
 
   read_token_parameters(extra_file_hash, suffix_list, new_list_entry);
 }
@@ -2644,11 +2766,21 @@ void LoadArtworkConfig(struct ArtworkListInfo *artwork_info)
     artwork_info->num_property_mapping_entries = 0;
   }
 
+#if 1
+  if (!GFX_OVERRIDE_ARTWORK(artwork_info->type))
+#else
   if (!SETUP_OVERRIDE_ARTWORK(setup, artwork_info->type))
+#endif
   {
     /* first look for special artwork configured in level series config */
     filename_base = getCustomArtworkLevelConfigFilename(artwork_info->type);
 
+#if 0
+    printf("::: filename_base == '%s' [%s, %s]\n", filename_base,
+          leveldir_current->graphics_set,
+          leveldir_current->graphics_path);
+#endif
+
     if (fileExists(filename_base))
       LoadArtworkConfigFromFilename(artwork_info, filename_base);
   }
@@ -2695,6 +2827,22 @@ static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
 
     basename = file_list_entry->default_filename;
 
+    /* fail for cloned default artwork that has no default filename defined */
+    if (file_list_entry->default_is_cloned &&
+       strEqual(basename, UNDEFINED_FILENAME))
+    {
+      int error_mode = ERR_WARN;
+
+      /* we can get away without sounds and music, but not without graphics */
+      if (*listnode == NULL && artwork_info->type == ARTWORK_TYPE_GRAPHICS)
+       error_mode = ERR_EXIT;
+
+      Error(error_mode, "token '%s' was cloned and has no default filename",
+           file_list_entry->token);
+
+      return;
+    }
+
     /* dynamic artwork has no default filename / skip empty default artwork */
     if (basename == NULL || strEqual(basename, UNDEFINED_FILENAME))
       return;
@@ -2771,6 +2919,7 @@ static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
       error_mode = ERR_EXIT;
 
     Error(error_mode, "cannot load artwork file '%s'", basename);
+
     return;
   }
 }
@@ -2902,7 +3051,7 @@ void NotifyUserAboutErrorFile()
 
 #if DEBUG
 
-#define DEBUG_NUM_TIMESTAMPS           3
+#define DEBUG_NUM_TIMESTAMPS           5
 #define DEBUG_TIME_IN_MICROSECONDS     0
 
 #if DEBUG_TIME_IN_MICROSECONDS
@@ -2926,35 +3075,53 @@ static double Counter_Microseconds()
 }
 #endif
 
+char *debug_print_timestamp_get_padding(int padding_size)
+{
+  static char *padding = NULL;
+  int max_padding_size = 100;
+
+  if (padding == NULL)
+  {
+    padding = checked_calloc(max_padding_size + 1);
+    memset(padding, ' ', max_padding_size);
+  }
+
+  return &padding[MAX(0, max_padding_size - padding_size)];
+}
+
 void debug_print_timestamp(int counter_nr, char *message)
 {
-#if DEBUG_TIME_IN_MICROSECONDS
-  static double counter[DEBUG_NUM_TIMESTAMPS][2];
+  int indent_size = 8;
+  int padding_size = 40;
+  float timestamp_interval;
 
-  if (counter_nr >= DEBUG_NUM_TIMESTAMPS)
+  if (counter_nr < 0)
+    Error(ERR_EXIT, "debugging: invalid negative counter");
+  else if (counter_nr >= DEBUG_NUM_TIMESTAMPS)
     Error(ERR_EXIT, "debugging: increase DEBUG_NUM_TIMESTAMPS in misc.c");
 
-  counter[counter_nr][0] = Counter_Microseconds();
-
-  if (message)
-    printf("%s %.3f ms\n", message,
-          (counter[counter_nr][0] - counter[counter_nr][1]) / 1000);
+#if DEBUG_TIME_IN_MICROSECONDS
+  static double counter[DEBUG_NUM_TIMESTAMPS][2];
+  char *unit = "ms";
 
-  counter[counter_nr][1] = counter[counter_nr][0];
+  counter[counter_nr][0] = Counter_Microseconds();
 #else
   static long counter[DEBUG_NUM_TIMESTAMPS][2];
-
-  if (counter_nr >= DEBUG_NUM_TIMESTAMPS)
-    Error(ERR_EXIT, "debugging: increase DEBUG_NUM_TIMESTAMPS in misc.c");
+  char *unit = "s";
 
   counter[counter_nr][0] = Counter();
+#endif
 
-  if (message)
-    printf("%s %.3f s\n", message,
-          (float)(counter[counter_nr][0] - counter[counter_nr][1]) / 1000);
-
+  timestamp_interval = counter[counter_nr][0] - counter[counter_nr][1];
   counter[counter_nr][1] = counter[counter_nr][0];
-#endif
+
+  if (message)
+    printf("%s%s%s %.3f %s\n",
+          debug_print_timestamp_get_padding(counter_nr * indent_size),
+          message,
+          debug_print_timestamp_get_padding(padding_size - strlen(message)),
+          timestamp_interval / 1000,
+          unit);
 }
 
 void debug_print_parent_only(char *format, ...)