added optional button to restart game (door, panel and touch variants)
[rocksndiamonds.git] / src / libgame / misc.c
index b1f4b66c755555bca3a567e915171333a1fa3950..536d90b53816d3b4ab11e26f28ed0f54edd9842e 100644 (file)
@@ -41,8 +41,7 @@
 // logging functions
 // ----------------------------------------------------------------------------
 
-#define DUPLICATE_LOG_OUT_TO_STDOUT            TRUE
-#define DUPLICATE_LOG_ERR_TO_STDERR            TRUE
+#define DUPLICATE_LOGGING_TO_STDOUT            TRUE
 
 
 #if defined(PLATFORM_ANDROID)
@@ -94,15 +93,15 @@ static void vprintf_log(char *format, va_list ap)
 
 static void vprintf_log_nonewline(char *format, va_list ap)
 {
-  FILE *file = program.log_file[LOG_ERR_ID];
+  FILE *file = program.log_file;
 
-#if DUPLICATE_LOG_ERR_TO_STDERR
-  if (file != program.log_file_default[LOG_ERR_ID])
+#if DUPLICATE_LOGGING_TO_STDOUT
+  if (file != program.log_file_default)
   {
     va_list ap2;
     va_copy(ap2, ap);
 
-    vfprintf(program.log_file_default[LOG_ERR_ID], format, ap2);
+    vfprintf(program.log_file_default, format, ap2);
 
     va_end(ap2);
   }
@@ -113,17 +112,17 @@ static void vprintf_log_nonewline(char *format, va_list ap)
 
 static void vprintf_log(char *format, va_list ap)
 {
-  FILE *file = program.log_file[LOG_ERR_ID];
+  FILE *file = program.log_file;
   char *newline = STRING_NEWLINE;
 
-#if DUPLICATE_LOG_ERR_TO_STDERR
-  if (file != program.log_file_default[LOG_ERR_ID])
+#if DUPLICATE_LOGGING_TO_STDOUT
+  if (file != program.log_file_default)
   {
     va_list ap2;
     va_copy(ap2, ap);
 
-    vfprintf(program.log_file_default[LOG_ERR_ID], format, ap2);
-    fprintf(program.log_file_default[LOG_ERR_ID], "%s", newline);
+    vfprintf(program.log_file_default, format, ap2);
+    fprintf(program.log_file_default, "%s", newline);
 
     va_end(ap2);
   }
@@ -196,15 +195,15 @@ void printf_line_with_prefix(char *prefix, char *line_chars, int line_length)
 
 static void vPrint(char *format, va_list ap)
 {
-  FILE *file = program.log_file[LOG_OUT_ID];
+  FILE *file = program.log_file;
 
-#if DUPLICATE_LOG_OUT_TO_STDOUT
-  if (file != program.log_file_default[LOG_OUT_ID])
+#if DUPLICATE_LOGGING_TO_STDOUT
+  if (file != program.log_file_default)
   {
     va_list ap2;
     va_copy(ap2, ap);
 
-    vfprintf(program.log_file_default[LOG_OUT_ID], format, ap2);
+    vfprintf(program.log_file_default, format, ap2);
 
     va_end(ap2);
   }
@@ -224,7 +223,7 @@ void Print(char *format, ...)
 
 void PrintNoLog(char *format, ...)
 {
-  FILE *file = program.log_file_default[LOG_OUT_ID];
+  FILE *file = program.log_file_default;
   va_list ap;
 
   va_start(ap, format);
@@ -1089,7 +1088,9 @@ char *getBasePath(char *filename)
 // various string functions
 // ----------------------------------------------------------------------------
 
-char *getStringCat2WithSeparator(char *s1, char *s2, char *sep)
+char *getStringCat2WithSeparator(const char *s1,
+                                const char *s2,
+                                const char *sep)
 {
   if (s1 == NULL || s2 == NULL || sep == NULL)
     return NULL;
@@ -1102,7 +1103,10 @@ char *getStringCat2WithSeparator(char *s1, char *s2, char *sep)
   return complete_string;
 }
 
-char *getStringCat3WithSeparator(char *s1, char *s2, char *s3, char *sep)
+char *getStringCat3WithSeparator(const char *s1,
+                                const char *s2,
+                                const char *s3,
+                                const char *sep)
 {
   if (s1 == NULL || s2 == NULL || s3 == NULL || sep == NULL)
     return NULL;
@@ -1116,17 +1120,17 @@ char *getStringCat3WithSeparator(char *s1, char *s2, char *s3, char *sep)
   return complete_string;
 }
 
-char *getStringCat2(char *s1, char *s2)
+char *getStringCat2(const char *s1, const char *s2)
 {
   return getStringCat2WithSeparator(s1, s2, "");
 }
 
-char *getStringCat3(char *s1, char *s2, char *s3)
+char *getStringCat3(const char *s1, const char *s2, const char *s3)
 {
   return getStringCat3WithSeparator(s1, s2, s3, "");
 }
 
-char *getPath2(char *path1, char *path2)
+char *getPath2(const char *path1, const char *path2)
 {
 #if defined(PLATFORM_ANDROID)
   // workaround for reading from assets directory -- skip "." subdirs in path
@@ -1139,7 +1143,7 @@ char *getPath2(char *path1, char *path2)
   return getStringCat2WithSeparator(path1, path2, STRING_PATH_SEPARATOR);
 }
 
-char *getPath3(char *path1, char *path2, char *path3)
+char *getPath3(const char *path1, const char *path2, const char *path3)
 {
 #if defined(PLATFORM_ANDROID)
   // workaround for reading from assets directory -- skip "." subdirs in path
@@ -1167,12 +1171,12 @@ static char *getPngOrPcxIfNotExists(char *filename)
   return filename;
 }
 
-char *getImg2(char *path1, char *path2)
+char *getImg2(const char *path1, const char *path2)
 {
   return getPngOrPcxIfNotExists(getPath2(path1, path2));
 }
 
-char *getImg3(char *path1, char *path2, char *path3)
+char *getImg3(const char *path1, const char *path2, const char *path3)
 {
   return getPngOrPcxIfNotExists(getPath3(path1, path2, path3));
 }
@@ -1228,14 +1232,14 @@ char *getStringToLower(const char *s)
   return s_copy;
 }
 
-void setString(char **old_value, char *new_value)
+void setString(char **old_value, const char *new_value)
 {
   checked_free(*old_value);
 
   *old_value = getStringCopy(new_value);
 }
 
-boolean strEqual(char *s1, char *s2)
+boolean strEqual(const char *s1, const char *s2)
 {
   return (s1 == NULL && s2 == NULL ? TRUE  :
          s1 == NULL && s2 != NULL ? FALSE :
@@ -1243,7 +1247,7 @@ boolean strEqual(char *s1, char *s2)
          strcmp(s1, s2) == 0);
 }
 
-boolean strEqualN(char *s1, char *s2, int n)
+boolean strEqualN(const char *s1, const char *s2, int n)
 {
   return (s1 == NULL && s2 == NULL ? TRUE  :
          s1 == NULL && s2 != NULL ? FALSE :
@@ -1251,7 +1255,7 @@ boolean strEqualN(char *s1, char *s2, int n)
          strncmp(s1, s2, n) == 0);
 }
 
-boolean strEqualCase(char *s1, char *s2)
+boolean strEqualCase(const char *s1, const char *s2)
 {
   return (s1 == NULL && s2 == NULL ? TRUE  :
          s1 == NULL && s2 != NULL ? FALSE :
@@ -1259,7 +1263,7 @@ boolean strEqualCase(char *s1, char *s2)
          strcasecmp(s1, s2) == 0);
 }
 
-boolean strEqualCaseN(char *s1, char *s2, int n)
+boolean strEqualCaseN(const char *s1, const char *s2, int n)
 {
   return (s1 == NULL && s2 == NULL ? TRUE  :
          s1 == NULL && s2 != NULL ? FALSE :
@@ -1267,7 +1271,7 @@ boolean strEqualCaseN(char *s1, char *s2, int n)
          strncasecmp(s1, s2, n) == 0);
 }
 
-boolean strPrefix(char *s, char *prefix)
+boolean strPrefix(const char *s, const char *prefix)
 {
   return (s == NULL && prefix == NULL ? TRUE  :
          s == NULL && prefix != NULL ? FALSE :
@@ -1275,7 +1279,7 @@ boolean strPrefix(char *s, char *prefix)
          strncmp(s, prefix, strlen(prefix)) == 0);
 }
 
-boolean strSuffix(char *s, char *suffix)
+boolean strSuffix(const char *s, const char *suffix)
 {
   return (s == NULL && suffix == NULL ? TRUE  :
          s == NULL && suffix != NULL ? FALSE :
@@ -1284,7 +1288,7 @@ boolean strSuffix(char *s, char *suffix)
          strcmp(&s[strlen(s) - strlen(suffix)], suffix) == 0);
 }
 
-boolean strPrefixLower(char *s, char *prefix)
+boolean strPrefixLower(const char *s, const char *prefix)
 {
   char *s_lower = getStringToLower(s);
   boolean match = strPrefix(s_lower, prefix);
@@ -1294,7 +1298,7 @@ boolean strPrefixLower(char *s, char *prefix)
   return match;
 }
 
-boolean strSuffixLower(char *s, char *suffix)
+boolean strSuffixLower(const char *s, const char *suffix)
 {
   char *s_lower = getStringToLower(s);
   boolean match = strSuffix(s_lower, suffix);
@@ -1304,7 +1308,7 @@ boolean strSuffixLower(char *s, char *suffix)
   return match;
 }
 
-boolean isURL(char *s)
+boolean isURL(const char *s)
 {
   while (*s && *s >= 'a' && *s <= 'z')
     s++;
@@ -1683,6 +1687,31 @@ void swap_number_pairs(int *x1, int *y1, int *x2, int *y2)
   *y2 = help_y;
 }
 
+int get_number_of_bits(int bits)
+{
+  /*
+    Counting bits set, Brian Kernighan's way
+
+    Brian Kernighan's method goes through as many iterations as there are set
+    bits. So if we have a 32-bit word with only the high bit set, then it will
+    only go once through the loop.
+
+    Published in 1988, the C Programming Language 2nd Ed. (by Brian W. Kernighan
+    and Dennis M. Ritchie) mentions this in exercise 2-9.
+    First published by Peter Wegner in CACM 3 (1960), 322.
+  */
+
+  int num_bits = 0;
+
+  while (bits)
+  {
+    bits &= bits - 1;  // clear the least significant bit set
+    num_bits++;
+  }
+
+  return num_bits;
+}
+
 /* the "put" variants of the following file access functions check for the file
    pointer being != NULL and return the number of bytes they have or would have
    written; this allows for chunk writing functions to first determine the size
@@ -3048,7 +3077,7 @@ void freeDirectoryEntry(DirectoryEntry *dir_entry)
 // functions for checking files and filenames
 // ----------------------------------------------------------------------------
 
-boolean directoryExists(char *dir_name)
+boolean directoryExists(const char *dir_name)
 {
   if (dir_name == NULL)
     return FALSE;
@@ -3076,7 +3105,7 @@ boolean directoryExists(char *dir_name)
   return success;
 }
 
-boolean fileExists(char *filename)
+boolean fileExists(const char *filename)
 {
   if (filename == NULL)
     return FALSE;
@@ -3100,7 +3129,7 @@ boolean fileExists(char *filename)
 }
 
 #if 0
-static boolean fileHasPrefix(char *basename, char *prefix)
+static boolean fileHasPrefix(const char *basename, const char *prefix)
 {
   static char *basename_lower = NULL;
   int basename_length, prefix_length;
@@ -3123,7 +3152,7 @@ static boolean fileHasPrefix(char *basename, char *prefix)
 }
 #endif
 
-static boolean fileHasSuffix(char *basename, char *suffix)
+static boolean fileHasSuffix(const char *basename, const char *suffix)
 {
   static char *basename_lower = NULL;
   int basename_length, suffix_length;
@@ -4180,45 +4209,41 @@ void FreeCustomArtworkLists(struct ArtworkListInfo *artwork_info)
 // (now also added for Windows, to create files in user data directory)
 // ----------------------------------------------------------------------------
 
+char *getLogBasename(char *basename)
+{
+  return getStringCat2(basename, ".log");
+}
+
 char *getLogFilename(char *basename)
 {
   return getPath2(getMainUserGameDataDir(), basename);
 }
 
-void OpenLogFiles(void)
+void OpenLogFile(void)
 {
-  int i;
-
   InitMainUserDataDirectory();
 
-  for (i = 0; i < NUM_LOGS; i++)
+  if ((program.log_file = fopen(program.log_filename, MODE_WRITE)) == NULL)
   {
-    if ((program.log_file[i] = fopen(program.log_filename[i], MODE_WRITE))
-       == NULL)
-    {
-      program.log_file[i] = program.log_file_default[i];   // reset to default
+    program.log_file = program.log_file_default;   // reset to default
 
-      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
-    setbuf(program.log_file[i], NULL);
+    Warn("cannot open file '%s' for writing: %s",
+        program.log_filename, strerror(errno));
   }
+
+  // output should be unbuffered so it is not truncated in a crash
+  setbuf(program.log_file, NULL);
 }
 
-void CloseLogFiles(void)
+void CloseLogFile(void)
 {
-  int i;
-
-  for (i = 0; i < NUM_LOGS; i++)
-    if (program.log_file[i] != program.log_file_default[i])
-      fclose(program.log_file[i]);
+  if (program.log_file != program.log_file_default)
+    fclose(program.log_file);
 }
 
-void DumpLogFile(int nr)
+void DumpLogFile(void)
 {
-  FILE *log_file = fopen(program.log_filename[nr], MODE_READ);
+  FILE *log_file = fopen(program.log_filename, MODE_READ);
 
   if (log_file == NULL)
     return;
@@ -4236,7 +4261,7 @@ void NotifyUserAboutErrorFile(void)
   char *error_text = getStringCat2("The program was aborted due to an error; "
                                   "for details, see the following error file:"
                                   STRING_NEWLINE,
-                                  program.log_filename[LOG_ERR_ID]);
+                                  program.log_filename);
 
   MessageBox(NULL, error_text, title_text, MB_OK);
 #endif