replaced glib function calls to g_memdup()
[rocksndiamonds.git] / src / game_bd / bd_cave.c
index 2ffb071e365097f3b117888785b61a8c606bd91d..197bec5e4a10282276fc36bf05ac747774f8f562 100644 (file)
@@ -81,7 +81,7 @@ static const char* scheduling_filename[] =
   "bd2ckatari"
 };
 
-static GHashTable *name_to_element;
+static HashTable *name_to_element;
 GdElement gd_char_to_element[256];
 
 /* color of flashing the screen, gate opening to exit */
@@ -247,7 +247,7 @@ void gd_create_char_to_element_table(void)
 
     if (c)
     {
-      if (gd_char_to_element[c]!=O_UNKNOWN)
+      if (gd_char_to_element[c] != O_UNKNOWN)
        Warn("Character %c already used for element %x", c, gd_char_to_element[c]);
 
       gd_char_to_element[c] = i;
@@ -275,9 +275,8 @@ void gd_cave_init(void)
 
   /* put names to a hash table */
   /* this is a helper for file read operations */
-  /* maps g_strdupped strings to elemenets (integers) */
-  name_to_element = g_hash_table_new_full(gd_str_case_hash, gd_str_case_equal,
-                                         free, NULL);
+  /* maps copied strings to elements (integers) */
+  name_to_element = create_hashtable(gd_str_case_hash, gd_str_case_equal, NULL, NULL);
 
   for (i = 0; i < O_MAX; i++)
   {
@@ -285,36 +284,36 @@ void gd_cave_init(void)
 
     key = g_ascii_strup(gd_elements[i].filename, -1);
 
-    if (g_hash_table_lookup_extended(name_to_element, key, NULL, NULL))
+    if (hashtable_exists(name_to_element, key))                /* hash value may be 0 */
       Warn("Name %s already used for element %x", key, i);
 
-    g_hash_table_insert(name_to_element, key, GINT_TO_POINTER(i));
+    hashtable_insert(name_to_element, key, INT_TO_PTR(i));
     /* ^^^ do not free "key", as hash table needs it during the whole time! */
 
-    key = g_strdup_printf("SCANNED_%s", key);        /* new string */
+    key = getStringCat2("SCANNED_", key);              /* new string */
 
-    g_hash_table_insert(name_to_element, key, GINT_TO_POINTER(i));
+    hashtable_insert(name_to_element, key, INT_TO_PTR(i));
     /* once again, do not free "key" ^^^ */
   }
 
   /* for compatibility with tim stridmann's memorydump->bdcff converter... .... ... */
-  g_hash_table_insert(name_to_element, "HEXPANDING_WALL", GINT_TO_POINTER(O_H_EXPANDING_WALL));
-  g_hash_table_insert(name_to_element, "FALLING_DIAMOND", GINT_TO_POINTER(O_DIAMOND_F));
-  g_hash_table_insert(name_to_element, "FALLING_BOULDER", GINT_TO_POINTER(O_STONE_F));
-  g_hash_table_insert(name_to_element, "EXPLOSION1S", GINT_TO_POINTER(O_EXPLODE_1));
-  g_hash_table_insert(name_to_element, "EXPLOSION2S", GINT_TO_POINTER(O_EXPLODE_2));
-  g_hash_table_insert(name_to_element, "EXPLOSION3S", GINT_TO_POINTER(O_EXPLODE_3));
-  g_hash_table_insert(name_to_element, "EXPLOSION4S", GINT_TO_POINTER(O_EXPLODE_4));
-  g_hash_table_insert(name_to_element, "EXPLOSION5S", GINT_TO_POINTER(O_EXPLODE_5));
-  g_hash_table_insert(name_to_element, "EXPLOSION1D", GINT_TO_POINTER(O_PRE_DIA_1));
-  g_hash_table_insert(name_to_element, "EXPLOSION2D", GINT_TO_POINTER(O_PRE_DIA_2));
-  g_hash_table_insert(name_to_element, "EXPLOSION3D", GINT_TO_POINTER(O_PRE_DIA_3));
-  g_hash_table_insert(name_to_element, "EXPLOSION4D", GINT_TO_POINTER(O_PRE_DIA_4));
-  g_hash_table_insert(name_to_element, "EXPLOSION5D", GINT_TO_POINTER(O_PRE_DIA_5));
-  g_hash_table_insert(name_to_element, "WALL2", GINT_TO_POINTER(O_STEEL_EXPLODABLE));
+  hashtable_insert(name_to_element, "HEXPANDING_WALL", INT_TO_PTR(O_H_EXPANDING_WALL));
+  hashtable_insert(name_to_element, "FALLING_DIAMOND", INT_TO_PTR(O_DIAMOND_F));
+  hashtable_insert(name_to_element, "FALLING_BOULDER", INT_TO_PTR(O_STONE_F));
+  hashtable_insert(name_to_element, "EXPLOSION1S", INT_TO_PTR(O_EXPLODE_1));
+  hashtable_insert(name_to_element, "EXPLOSION2S", INT_TO_PTR(O_EXPLODE_2));
+  hashtable_insert(name_to_element, "EXPLOSION3S", INT_TO_PTR(O_EXPLODE_3));
+  hashtable_insert(name_to_element, "EXPLOSION4S", INT_TO_PTR(O_EXPLODE_4));
+  hashtable_insert(name_to_element, "EXPLOSION5S", INT_TO_PTR(O_EXPLODE_5));
+  hashtable_insert(name_to_element, "EXPLOSION1D", INT_TO_PTR(O_PRE_DIA_1));
+  hashtable_insert(name_to_element, "EXPLOSION2D", INT_TO_PTR(O_PRE_DIA_2));
+  hashtable_insert(name_to_element, "EXPLOSION3D", INT_TO_PTR(O_PRE_DIA_3));
+  hashtable_insert(name_to_element, "EXPLOSION4D", INT_TO_PTR(O_PRE_DIA_4));
+  hashtable_insert(name_to_element, "EXPLOSION5D", INT_TO_PTR(O_PRE_DIA_5));
+  hashtable_insert(name_to_element, "WALL2", INT_TO_PTR(O_STEEL_EXPLODABLE));
 
   /* compatibility with old bd-faq (pre disassembly of bladder) */
-  g_hash_table_insert(name_to_element, "BLADDERd9", GINT_TO_POINTER(O_BLADDER_8));
+  hashtable_insert(name_to_element, "BLADDERd9", INT_TO_PTR(O_BLADDER_8));
 
   /* create table to show errors at the start of the application */
   gd_create_char_to_element_table();
@@ -324,7 +323,7 @@ void gd_cave_init(void)
 GdElement gd_get_element_from_string (const char *string)
 {
   char *upper = g_ascii_strup(string, -1);
-  gpointer value;
+  void *value;
   boolean found;
 
   if (!string)
@@ -333,12 +332,15 @@ GdElement gd_get_element_from_string (const char *string)
     return O_UNKNOWN;
   }
 
-  found = g_hash_table_lookup_extended(name_to_element, upper, NULL, &value);
+  found = hashtable_exists(name_to_element, upper);    /* hash value may be 0 */
+  if (found)
+    value = hashtable_search(name_to_element, upper);
   free(upper);
   if (found)
-    return (GdElement) (GPOINTER_TO_INT(value));
+    return (GdElement) (PTR_TO_INT(value));
+
+  Warn("Invalid string representing element: '%s'", string);
 
-  Warn("Invalid string representing element: %s", string);
   return O_UNKNOWN;
 }
 
@@ -421,19 +423,18 @@ int gd_add_highscore(GdHighScore *highscores, const char *name, int score)
 }
 
 /* for the case-insensitive hash keys */
-boolean gd_str_case_equal(gconstpointer s1, gconstpointer s2)
+int gd_str_case_equal(void *s1, void *s2)
 {
   return strcasecmp(s1, s2) == 0;
 }
 
-guint gd_str_case_hash(gconstpointer v)
+unsigned int gd_str_case_hash(void *v)
 {
-  char *upper;
-  guint hash;
+  char *upper = getStringToUpper(v);
+  unsigned int hash = get_hash_from_string(upper);
 
-  upper = g_ascii_strup(v, -1);
-  hash = g_str_hash(v);
   free(upper);
+
   return hash;
 }
 
@@ -443,18 +444,12 @@ guint gd_str_case_hash(gconstpointer v)
 */
 GdCave *gd_cave_new(void)
 {
-  int i;
   GdCave *cave;
 
   cave = checked_calloc(sizeof(GdCave));
 
   /* hash table which stores unknown tags as strings. */
-  cave->tags = g_hash_table_new_full(gd_str_case_hash, gd_str_case_equal, free, free);
-
-  /* for strings */
-  for (i = 0; gd_cave_properties[i].identifier != NULL; i++)
-    if (gd_cave_properties[i].type == GD_TYPE_LONGSTRING)
-      G_STRUCT_MEMBER(GString *, cave, gd_cave_properties[i].offset) = g_string_new(NULL);
+  cave->tags = create_hashtable(gd_str_case_hash, gd_str_case_equal, free, free);
 
   gd_cave_set_gdash_defaults(cave);
 
@@ -511,7 +506,7 @@ gpointer gd_cave_map_dup_size(const GdCave *cave, const gpointer map, const int
     return NULL;
 
   rows = checked_malloc((cave->h) * sizeof(gpointer));
-  rows[0] = g_memdup (maplines[0], cell_size * cave->w * cave->h);
+  rows[0] = getMemCopy (maplines[0], cell_size * cave->w * cave->h);
 
   for (y = 1; y < cave->h; y++)
     rows[y] = (char *)rows[0] + cell_size * cave->w * y;
@@ -541,15 +536,15 @@ void gd_cave_free(GdCave *cave)
     return;
 
   if (cave->tags)
-    g_hash_table_destroy(cave->tags);
+    hashtable_destroy(cave->tags);
 
   if (cave->random)    /* random generator is a GRand * */
     g_rand_free(cave->random);
 
-  /* free GStrings */
+  /* free strings */
   for (i = 0; gd_cave_properties[i].identifier != NULL; i++)
-    if (gd_cave_properties[i].type==GD_TYPE_LONGSTRING)
-      g_string_free(G_STRUCT_MEMBER(GString *, cave, gd_cave_properties[i].offset), TRUE);
+    if (gd_cave_properties[i].type == GD_TYPE_LONGSTRING)
+      checked_free(G_STRUCT_MEMBER(char *, cave, gd_cave_properties[i].offset));
 
   /* map */
   gd_cave_map_free(cave->map);
@@ -572,9 +567,9 @@ void gd_cave_free(GdCave *cave)
   free (cave);
 }
 
-static void hash_copy_foreach(const char *key, const char *value, GHashTable *dest)
+static void hash_copy_foreach(const char *key, const char *value, HashTable *dest)
 {
-  g_hash_table_insert(dest, g_strdup(key), g_strdup(value));
+  hashtable_insert(dest, getStringCopy(key), getStringCopy(value));
 }
 
 /* copy cave from src to destination, with duplicating dynamically allocated data */
@@ -586,19 +581,19 @@ void gd_cave_copy(GdCave *dest, const GdCave *src)
   g_memmove(dest, src, sizeof(GdCave));
 
   /* but duplicate dynamic data */
-  dest->tags = g_hash_table_new_full(gd_str_case_hash, gd_str_case_equal,
-                                    free, free);
+  dest->tags = create_hashtable(gd_str_case_hash, gd_str_case_equal, free, free);
+
   if (src->tags)
-    g_hash_table_foreach(src->tags, (GHFunc) hash_copy_foreach, dest->tags);
+    hashtable_foreach(src->tags, (hashtable_fn)hash_copy_foreach, dest->tags);
 
   dest->map = gd_cave_map_dup(src, map);
   dest->hammered_reappear = gd_cave_map_dup(src, hammered_reappear);
 
   /* for longstrings */
   for (i = 0; gd_cave_properties[i].identifier != NULL; i++)
-    if (gd_cave_properties[i].type==GD_TYPE_LONGSTRING)
-      G_STRUCT_MEMBER(GString *, dest, gd_cave_properties[i].offset) =
-       g_string_new(G_STRUCT_MEMBER(GString *, src, gd_cave_properties[i].offset)->str);
+    if (gd_cave_properties[i].type == GD_TYPE_LONGSTRING)
+      G_STRUCT_MEMBER(char *, dest, gd_cave_properties[i].offset) =
+       getStringCopy(G_STRUCT_MEMBER(char *, src, gd_cave_properties[i].offset));
 
   /* no reason to copy this */
   dest->objects_order = NULL;
@@ -610,7 +605,7 @@ void gd_cave_copy(GdCave *dest, const GdCave *src)
 
     dest->objects = NULL;    /* new empty list */
     for (iter = src->objects; iter != NULL; iter = iter->next) /* do a deep copy */
-      dest->objects = g_list_append(dest->objects, g_memdup (iter->data, sizeof (GdObject)));
+      dest->objects = g_list_append(dest->objects, getMemCopy (iter->data, sizeof (GdObject)));
   }
 
   /* copy replays */
@@ -879,9 +874,9 @@ void gd_cave_auto_shrink(GdCave *cave)
          case O_INBOX:
            /* shrink only lines, which have only ONE player or outbox.
               this is for bd4 intermission 2, for example. */
-           if (empty==STEEL_OR_OTHER)
+           if (empty == STEEL_OR_OTHER)
              empty = NO_SHRINK;
-           if (empty==STEEL_ONLY)
+           if (empty == STEEL_ONLY)
              empty = STEEL_OR_OTHER;
            break;
 
@@ -914,9 +909,9 @@ void gd_cave_auto_shrink(GdCave *cave)
          case O_PRE_OUTBOX:
          case O_PRE_INVIS_OUTBOX:
          case O_INBOX:
-           if (empty==STEEL_OR_OTHER)
+           if (empty == STEEL_OR_OTHER)
              empty = NO_SHRINK;
-           if (empty==STEEL_ONLY)
+           if (empty == STEEL_ONLY)
              empty = STEEL_OR_OTHER;
            break;
 
@@ -951,9 +946,9 @@ void gd_cave_auto_shrink(GdCave *cave)
          case O_PRE_OUTBOX:
          case O_PRE_INVIS_OUTBOX:
          case O_INBOX:
-           if (empty==STEEL_OR_OTHER)
+           if (empty == STEEL_OR_OTHER)
              empty = NO_SHRINK;
-           if (empty==STEEL_ONLY)
+           if (empty == STEEL_ONLY)
              empty = STEEL_OR_OTHER;
            break;
 
@@ -1299,7 +1294,7 @@ void gd_drawcave_game(const GdCave *cave, int **element_buffer, int **gfx_buffer
 
   /* player with bomb does not blink or tap - no graphics drawn for that.
      running is drawn using w/o bomb cells */
-  if (cave->last_direction!=GD_MV_STILL)
+  if (cave->last_direction != GD_MV_STILL)
   {
     elemmapping[O_PLAYER_BOMB] = map;
     elemdrawing[O_PLAYER_BOMB] = draw;
@@ -1396,8 +1391,6 @@ GdReplay *gd_replay_new(void)
 
   rep = checked_calloc(sizeof(GdReplay));
 
-  /* create dynamic objects */
-  rep->comment = g_string_new(NULL);
   rep->movements = g_byte_array_new();
 
   return rep;
@@ -1407,10 +1400,10 @@ GdReplay *gd_replay_new_from_replay(GdReplay *orig)
 {
   GdReplay *rep;
 
-  rep = g_memdup(orig, sizeof(GdReplay));
+  rep = getMemCopy(orig, sizeof(GdReplay));
 
   /* replicate dynamic data */
-  rep->comment = g_string_new(orig->comment->str);
+  rep->comment = getStringCopy(orig->comment);
   rep->movements = g_byte_array_new();
   g_byte_array_append(rep->movements, orig->movements->data, orig->movements->len);
 
@@ -1420,7 +1413,7 @@ GdReplay *gd_replay_new_from_replay(GdReplay *orig)
 void gd_replay_free(GdReplay *replay)
 {
   g_byte_array_free(replay->movements, TRUE);
-  g_string_free(replay->comment, TRUE);
+  checked_free(replay->comment);
   free(replay);
 }
 
@@ -1437,125 +1430,6 @@ void gd_replay_store_movement(GdReplay *replay, GdDirection player_move,
   g_byte_array_append(replay->movements, data, 1);
 }
 
-/* get next available movement from a replay; store variables to player_move,
-   player_fire, suicide */
-/* return true if successful */
-boolean gd_replay_get_next_movement(GdReplay *replay, GdDirection *player_move,
-                                   boolean *player_fire, boolean *suicide)
-{
-  guint8 data;
-
-  /* if no more available movements */
-  if (replay->current_playing_pos >= replay->movements->len)
-    return FALSE;
-
-  data = replay->movements->data[replay->current_playing_pos++];
-  *suicide = (data & GD_REPLAY_SUICIDE_MASK) != 0;
-  *player_fire = (data & GD_REPLAY_FIRE_MASK) != 0;
-  *player_move = (data & GD_REPLAY_MOVE_MASK);
-
-  return TRUE;
-}
-
-void gd_replay_rewind(GdReplay *replay)
-{
-  replay->current_playing_pos = 0;
-}
-
-#define REPLAY_BDCFF_UP                        "u"
-#define REPLAY_BDCFF_UP_RIGHT          "ur"
-#define REPLAY_BDCFF_RIGHT             "r"
-#define REPLAY_BDCFF_DOWN_RIGHT                "dr"
-#define REPLAY_BDCFF_DOWN              "d"
-#define REPLAY_BDCFF_DOWN_LEFT         "dl"
-#define REPLAY_BDCFF_LEFT              "l"
-#define REPLAY_BDCFF_UP_LEFT           "ul"
-/* when not moving */
-#define REPLAY_BDCFF_STILL             "."
-/* when the fire is pressed */
-#define REPLAY_BDCFF_FIRE              "F"
-#define REPLAY_BDCFF_SUICIDE           "k"
-
-static char *direction_to_bdcff(GdDirection mov)
-{
-  switch (mov)
-  {
-    /* not moving */
-    case GD_MV_STILL:          return REPLAY_BDCFF_STILL;
-
-      /* directions */
-    case GD_MV_UP:             return REPLAY_BDCFF_UP;
-    case GD_MV_UP_RIGHT:       return REPLAY_BDCFF_UP_RIGHT;
-    case GD_MV_RIGHT:          return REPLAY_BDCFF_RIGHT;
-    case GD_MV_DOWN_RIGHT:     return REPLAY_BDCFF_DOWN_RIGHT;
-    case GD_MV_DOWN:           return REPLAY_BDCFF_DOWN;
-    case GD_MV_DOWN_LEFT:      return REPLAY_BDCFF_DOWN_LEFT;
-    case GD_MV_LEFT:           return REPLAY_BDCFF_LEFT;
-    case GD_MV_UP_LEFT:                return REPLAY_BDCFF_UP_LEFT;
-
-    default:
-      return REPLAY_BDCFF_STILL;
-  }
-}
-
-/* same as above; pressing fire will be a capital letter. */
-static char *direction_fire_to_bdcff(GdDirection dir, boolean fire)
-{
-  static char mov[10];
-
-  strcpy(mov, direction_to_bdcff(dir));
-
-  if (fire)
-  {
-    int i;
-
-    for (i = 0; mov[i] != 0; i++)
-      mov[i] = g_ascii_toupper(mov[i]);
-  }
-
-  return mov;
-}
-
-char *gd_replay_movements_to_bdcff(GdReplay *replay)
-{
-  int pos;
-  GString *str;
-
-  str = g_string_new(NULL);
-
-  for (pos = 0; pos < replay->movements->len; pos++)
-  {
-    int num = 1;
-    guint8 data;
-
-    /* if this is not the first movement, append a space. */
-    if (str->len != 0)
-      g_string_append_c(str, ' ');
-
-    /* if same byte appears, count number of occurrences - something like an rle compression. */
-    /* be sure not to cross the array boundaries */
-    while (pos < replay->movements->len - 1 &&
-          replay->movements->data[pos] == replay->movements->data[pos + 1])
-    {
-      pos++;
-      num++;
-    }
-
-    data = replay->movements->data[pos];
-
-    if (data & GD_REPLAY_SUICIDE_MASK)
-      g_string_append(str, REPLAY_BDCFF_SUICIDE);
-
-    g_string_append(str, direction_fire_to_bdcff(data & GD_REPLAY_MOVE_MASK,
-                                                data & GD_REPLAY_FIRE_MASK));
-
-    if (num != 1)
-      g_string_append_printf(str, "%d", num);
-  }
-
-  return g_string_free(str, FALSE);
-}
-
 /* calculate adler checksum for a rendered cave; this can be used for more caves. */
 void gd_cave_adler_checksum_more(GdCave *cave, guint32 *a, guint32 *b)
 {