toc/
toc/account/a/
toc/area/backup/
toc/area/imc/
toc/caste/
toc/caste/backup/
toc/clans/
toc/classes/
toc/crash/
toc/gods/
toc/guilds/
toc/lname/s/
toc/maps/backup/
toc/player/a/
toc/src/
toc/system/backup/
toc/tableprog/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |   \\._.//   *
 * -----------------------------------------------------------|   (0...0)   *
 * SMAUG 1.4 (C) 1994, 1995, 1996, 1998  by Derek Snider      |    ).:.(    *
 * -----------------------------------------------------------|    {o o}    *
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |   / ' ' \   *
 * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek,      |~'~.VxvxV.~'~*
 * Tricops and Fireblade                                      |             *
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.     *
 * ------------------------------------------------------------------------ *
 *        Memory Cleanup  -Druid                                            *
 ****************************************************************************
 *
 * PirateMUD is a derivative work of SMAUG and therefore the SMAUG License, 
 * Merc License, and Diku License must all be followed, no exceptions. The
 * PirateMUD license simply states, "AS IS".
 * 
 * This by no means cleans all the memory, there is stuff that my mud doesn't
 * use, therefore the memory is not allocated, and hence it may not be cleaned
 * up in here.
 *
 * First, Add this file to the Makefile
 *
 * At the top of comm.c
 * Add:
 * void cleanup_memory( void );
 * Search for:
 * log_string( "Normal termination of game." );
 *
 * After that add:
 * log_string( "Cleaning up memory." );
 * cleanup_memory( );
 *
 * $Header: /home/ddruid/smaug/src/RCS/cleanup.c,v 0.4 2002/09/29 15:06:01 ddruid Exp ddruid $
 * Robert Haas  - $Date: 2002/09/29 15:06:01 $
 *
 * $Id: cleanup.c,v 0.4 2002/09/29 15:06:01 ddruid Exp ddruid $
 *
 * $State: Exp $
 *
 * REVISION HISTORY:
 * $Log: cleanup.c,v $
 * Revision 0.4  2002/09/29 15:06:01  ddruid
 * Had to modify the order a bit to fix a crash with Dmalloc.
 *
 * Revision 0.3  2002/09/03 19:43:22  ddruid
 * Random global variables
 *
 * Revision 0.2  2002/08/28 17:45:59  ddruid
 * Most things cleaned, seem to be catching global variables now.
 *
 * Revision 0.1  2002/08/27 23:04:26  ddruid
 * Check in
 *
 * Revision 0.0  2002/08/26 18:09:12  ddruid
 * Initial revision
 *
 * NOTES: 
 *  STRALLOC free with MY_STRFREE
 *  fread_string free with MY_STRFREE
 *  fread_string_nohash free with MY_DISPOSE 
 *  str_dup free with MY_DISPOSE
 */
#include <stdio.h>
#include "mud.h"

/* RCS Version */
static char clversion_rcsid[] __attribute__ ((unused)) = "$Id: cleanup.c,v 0.4 2002/09/29 15:06:01 ddruid Exp ddruid $";

extern MOB_INDEX_DATA *mob_index_hash[MAX_KEY_HASH];
extern ROOM_INDEX_DATA *room_index_hash[MAX_KEY_HASH];
extern OBJ_INDEX_DATA *obj_index_hash[MAX_KEY_HASH];
extern MAP_INDEX_DATA *first_map;
extern struct act_prog_data *room_act_list;
extern struct act_prog_data *obj_act_list;
extern char *ranged_target_name;

void unlink_social( SOCIALTYPE *social );
void free_desc( DESCRIPTOR_DATA *d );

#define MY_DISPOSE( ptr ) if( (ptr) ) DISPOSE( (ptr) );
#define MY_STRFREE( ptr ) if( (ptr) ) STRFREE( (ptr) );

/*
 * Print current version
 */
void do_clversion( CHAR_DATA *ch, char *argument )
{
  ch_printf_color( ch, "&RCurrent Cleanup_Mem version: &Y%s\n\r", clversion_rcsid );
  return;
}   /* do_clversion */

/*
 * Clean all memory on exit to help find leaks
 */
void cleanup_memory( void )
{

  int hash;
  CMDTYPE *command, *cmd_next;
  CLAN_DATA *clan, *clan_next;
  SOCIALTYPE *social, *social_next;
  struct class_type *class;
  struct race_type *race;
  SKILLTYPE *skill;
  SMAUG_AFF *aff, *aff_next;
  WATCH_DATA *pw, *pw_next;
  HELP_DATA *pHelp, *pHelp_next;
  LANG_DATA *lang, *lang_next;
  LCNV_DATA *lcnv, *lcnv_next;
  CHAR_DATA *character, *char_next;
  OBJ_DATA *object, *object_next;
  MOB_INDEX_DATA *mob, *mob_indx_next;
  ROOM_INDEX_DATA *room, *room_indx_next;
  OBJ_INDEX_DATA *obj, *obj_indx_next;
  AREA_DATA *area, *area_next;
  RESET_DATA *res, *res_next;
  MAP_INDEX_DATA *map, *map_next;
  DESCRIPTOR_DATA *desc, *desc_next;
  BOARD_DATA *board, *board_next;
  NOTE_DATA *note, *note_next;
  AFFECT_DATA *paf, *paf_next;
  EXTRA_DESCR_DATA *ed, *ed_next;
  MPROG_DATA *mp, *mp_next;
  struct act_prog_data *apd, *apd_next;

  /* Close open files */
  fprintf( stdout, "Closing reserve files.\n" );
  if( fpReserve )
    fclose( fpReserve );
  if( fpLOG )
    fclose( fpLOG );
    
  
  /* Whack supermob */
  fprintf( stdout, "Whacking supermob.\n" );
  if( supermob )
  {
    char_from_room( supermob );
    UNLINK( supermob, first_char, last_char, next, prev );
    free_char( supermob );
  }

  /* Descriptors */
  fprintf( stdout, "Descriptors.\n" );
  for( desc = first_descriptor; desc; desc = desc_next )
  {
    desc_next = desc->next;
    UNLINK( desc, first_descriptor, last_descriptor, next, prev );
    free_desc( desc );
  }

  /* Free Characters */
  fprintf( stdout, "Characters.\n" );
  for( character = first_char; character; character = char_next )
  {
    if( !character )
      break;
    char_next = character->next;
    UNLINK( character, first_char, last_char, next, prev );
    char_from_room( character );
    character->desc = NULL;
    character->first_carrying = NULL;
    character->last_carrying = NULL;
    free_char( character );
  }
  clean_char_queue(  );
  first_char = NULL;
  
  /* Mob Hash */
  fprintf( stdout, "Mob hash table.\n" );
  for( hash = 0; hash < MAX_KEY_HASH; hash++ )
  {
    for( mob = mob_index_hash[hash]; mob; mob = mob_indx_next )
    {
      mob_indx_next = mob->next;
      delete_mob( mob );
    }
  }
  
  /* Free Objects */
  fprintf( stdout, "Objects.\n" );
  clean_obj_queue(  );
  for( object = first_object; object; object = object_next )
  {
    object_next = object->next;
    UNLINK( object, first_object, last_object, next, prev );
    if( object->item_type == ITEM_PORTAL )
      remove_portal( object );
    
    
    /*if( object->carried_by )
      object->carried_by = NULL;
    if( object->in_room )
      obj_from_room( object );
    else if( object->in_obj )
      obj_from_obj( object );*/
    
    for( paf = object->first_affect; paf; paf = paf_next )
    {
      paf_next = paf->next;
      MY_DISPOSE( paf );
    }

    for( ed = object->first_extradesc; ed; ed = ed_next )
    {
      ed_next = ed->next;
      MY_STRFREE( ed->description );
      MY_STRFREE( ed->keyword );
      MY_DISPOSE( ed );
    }

    if( object->mpact )
    {
      MY_DISPOSE( object->mpact->buf );
      MY_DISPOSE( object->mpact );
    }
    MY_STRFREE( object->name );
    MY_STRFREE( object->description );
    MY_STRFREE( object->short_descr );
    MY_STRFREE( object->action_desc );
    MY_DISPOSE( object );
  }

  /* Commands */
  fprintf( stdout, "Commands.\n" );
  for( hash = 0; hash < 126; hash++ )
    for( command = command_hash[hash]; command; command = cmd_next )
    {
      cmd_next = command->next;
      command->next = NULL;
      command->do_fun = NULL;
      free_command( command );
    }

  /* Clans */
  fprintf( stdout, "Clans.\n" );
  for( clan = first_clan; clan; clan = clan_next )
  {
    clan_next = clan->next;

    MY_DISPOSE( clan->filename );
    MY_STRFREE( clan->name );
    MY_STRFREE( clan->motto );
    MY_STRFREE( clan->description );
    MY_STRFREE( clan->deity );
    MY_STRFREE( clan->leader );
    MY_STRFREE( clan->number1 );
    MY_STRFREE( clan->number2 );
    MY_STRFREE( clan->badge );
    MY_DISPOSE( clan );
  }

  /* Classes */
  fprintf( stdout, "Classes.\n" );
  for( hash = 0; hash < 0; hash++ )
  {
    class = class_table[hash];

    STRFREE( class->who_name );
    DISPOSE( class );
  }

  /* socials */
  fprintf( stdout, "Socials.\n" );
  for( hash = 0; hash < 27; hash++ )
    for( social = social_index[hash]; social; social = social_next )
    {
      social_next = social->next;
      free_social( social );
    }

  /* Skills */
  fprintf( stdout, "Skills.\n" );
  for( hash = 0; hash < top_sn; hash++ )
  {
    skill = skill_table[hash];

    if( skill->affects )
    {
      for( aff = skill->affects; aff; aff = aff_next )
      {
        aff_next = aff->next;

        MY_DISPOSE( aff->duration );
        MY_DISPOSE( aff->modifier );
        MY_DISPOSE( aff );
      }
    }
    MY_DISPOSE( skill->name );
    MY_DISPOSE( skill->noun_damage );
    MY_DISPOSE( skill->msg_off );
    MY_DISPOSE( skill->hit_char );
    MY_DISPOSE( skill->hit_vict );
    MY_DISPOSE( skill->hit_room );
    MY_DISPOSE( skill->hit_dest );
    MY_DISPOSE( skill->miss_char );
    MY_DISPOSE( skill->miss_vict );
    MY_DISPOSE( skill->miss_room );
    MY_DISPOSE( skill->die_char );
    MY_DISPOSE( skill->die_vict );
    MY_DISPOSE( skill->die_room );
    MY_DISPOSE( skill->imm_char );
    MY_DISPOSE( skill->imm_vict );
    MY_DISPOSE( skill->imm_room );
    MY_DISPOSE( skill->dice );
    MY_DISPOSE( skill->components );
    MY_DISPOSE( skill->teachers );
    skill->spell_fun = NULL;
    skill->skill_fun = NULL;
    MY_DISPOSE( skill );

  }

  /* Watches */
  fprintf( stdout, "Watches.\n" );
  for( pw = first_watch; pw; pw = pw_next )
  {
    pw_next = pw->next;
    MY_DISPOSE( pw->imm_name );
    MY_DISPOSE( pw->player_site );
    MY_DISPOSE( pw->target_name );
    UNLINK( pw, first_watch, last_watch, next, prev );
    MY_DISPOSE( pw );
  }

  /* Helps */
  fprintf( stdout, "Helps.\n" );
  for( pHelp = first_help; pHelp; pHelp = pHelp_next )
  {
    pHelp_next = pHelp->next;
    UNLINK( pHelp, first_help, last_help, next, prev );
    MY_STRFREE( pHelp->text );
    MY_STRFREE( pHelp->keyword );
    MY_DISPOSE( pHelp );
  }

  /* Races */
  fprintf( stdout, "Races.\n" );
  for( hash = 0; hash < MAX_RACE; hash++ )
  {
    race = race_table[hash];
    MY_DISPOSE( race );
  }

  /* Languages */
  fprintf( stdout, "Languages.\n" );
  for( lang = first_lang; lang; lang = lang_next )
  {
    lang_next = lang->next;

    for( lcnv = lang->first_precnv; lcnv; lcnv = lcnv_next )
    {
      lcnv_next = lcnv->next;
      UNLINK( lcnv, lang->first_precnv, lang->last_precnv, next, prev );
      MY_DISPOSE( lcnv->old );
      MY_DISPOSE( lcnv->new );
      MY_DISPOSE( lcnv );
    }
    for( lcnv = lang->first_cnv; lcnv; lcnv = lcnv_next )
    {
      lcnv_next = lcnv->next;
      UNLINK( lcnv, lang->first_cnv, lang->last_cnv, next, prev );
      MY_DISPOSE( lcnv->old );
      MY_DISPOSE( lcnv->new );
      MY_DISPOSE( lcnv );
    }
    MY_STRFREE( lang->name );
    MY_STRFREE( lang->alphabet );
    MY_DISPOSE( lang );
  }

  /* Boards */
  fprintf( stdout, "Boards.\n" );
  for( board = first_board; board; board = board_next )
  {
    board_next = board->next;

    for( note = board->first_note; note; note = note_next )
    {
      note_next = note->next;
      UNLINK( note, board->first_note, board->last_note, next, prev );
      free_note( note );
    }
    UNLINK( board, first_board, last_board, next, prev );
    MY_DISPOSE( board->extra_readers );
    MY_DISPOSE( board->extra_removers );
    MY_DISPOSE( board->note_file );
    MY_DISPOSE( board->read_group );
    MY_DISPOSE( board );
  }

  /* Rooms */
  fprintf( stdout, "Room hash table.\n" );
  for( hash = 0; hash < MAX_KEY_HASH; hash++ )
    for( room = room_index_hash[hash]; room; room = room_indx_next )
    {
      room_indx_next = room->next;
      room->first_content = NULL;
      room->last_content = NULL;
      delete_room( room );
    }

  /* Obj Hash */
  fprintf( stdout, "Object hash table.\n" );
  for( hash = 0; hash < MAX_KEY_HASH; hash++ )
    for( obj = obj_index_hash[hash]; obj; obj = obj_indx_next )
    {
      obj_indx_next = obj->next;

      for( ed = obj->first_extradesc; ed; ed = ed_next )
      {
        ed_next = ed->next;

        MY_STRFREE( ed->keyword );
        MY_STRFREE( ed->description );
        MY_DISPOSE( ed );
      }

      for( paf = obj->first_affect; paf; paf = paf_next )
      {
        paf_next = paf->next;

        MY_DISPOSE( paf );
      }

      for( mp = obj->mudprogs; mp; mp = mp_next )
      {
        mp_next = mp->next;
        MY_STRFREE( mp->arglist );
        MY_STRFREE( mp->comlist );
        MY_DISPOSE( mp );
      }

      MY_STRFREE( obj->name );
      MY_STRFREE( obj->short_descr );
      MY_STRFREE( obj->description );
      MY_STRFREE( obj->action_desc );
      MY_DISPOSE( obj );
    }

  /* Area data */
  fprintf( stdout, "Area data.\n" );
  for( area = first_area; area; area = area_next )
  {
    area_next = area->next;

    for( res = area->first_reset; res; res = res_next )
    {
      res_next = res->next;
      UNLINK( res, area->first_reset, area->last_reset, next, prev );
      MY_DISPOSE( res );
    }
    MY_DISPOSE( area->name );
    MY_DISPOSE( area->filename );
    MY_STRFREE( area->author );
    MY_DISPOSE( area->resetmsg );
    MY_DISPOSE( area );
  }

  /* Map Indexes */
  fprintf( stdout, "Map indexes.\n" );
  for( map = first_map; map; map = map_next )
  {
    map_next = map->next;
    DISPOSE( map );
  }

  /* Get rid of auction pointer  MUST BE AFTER OBJECTS DESTROYED */
  fprintf( stdout, "Auction.\n" );
  MY_DISPOSE( auction );

  /* System Data */
  fprintf( stdout, "System data.\n" );
  MY_DISPOSE( sysdata.time_of_max );
  MY_DISPOSE( sysdata.mud_name );
  MY_STRFREE( sysdata.guild_overseer );
  MY_STRFREE( sysdata.guild_advisor );

  /* Herbs */
  fprintf( stdout, "Herbs.\n" );
  for( hash = 0; hash < top_herb; hash++ )
  {
    skill = herb_table[hash];

    if( skill->affects )
    {
      for( aff = skill->affects; aff; aff = aff_next )
      {
        aff_next = aff->next;

        MY_DISPOSE( aff->duration );
        MY_DISPOSE( aff->modifier );
        MY_DISPOSE( aff );
      }
    }
    MY_DISPOSE( skill->name );
    MY_DISPOSE( skill->noun_damage );
    MY_DISPOSE( skill->msg_off );
    MY_DISPOSE( skill->hit_char );
    MY_DISPOSE( skill->hit_vict );
    MY_DISPOSE( skill->hit_room );
    MY_DISPOSE( skill->hit_dest );
    MY_DISPOSE( skill->miss_char );
    MY_DISPOSE( skill->miss_vict );
    MY_DISPOSE( skill->miss_room );
    MY_DISPOSE( skill->die_char );
    MY_DISPOSE( skill->die_vict );
    MY_DISPOSE( skill->die_room );
    MY_DISPOSE( skill->imm_char );
    MY_DISPOSE( skill->imm_vict );
    MY_DISPOSE( skill->imm_room );
    MY_DISPOSE( skill->dice );
    MY_DISPOSE( skill->components );
    MY_DISPOSE( skill->teachers );
    skill->spell_fun = NULL;
    skill->skill_fun = NULL;
    MY_DISPOSE( skill );
  }

  /* Prog Act lists */
  fprintf( stdout, "Mprog act list.\n" );
  for( apd = mob_act_list; apd; apd = apd_next )
  {
    apd_next = apd->next;
    MY_DISPOSE( apd );
  }
  
  fprintf( stdout, "Rprog act list.\n" );
  for( apd = room_act_list; apd; apd = apd_next )
  {
    apd_next = apd->next;
    MY_DISPOSE( apd );
  }
  
  fprintf( stdout, "Oprog act list.\n" );
  for( apd = obj_act_list; apd; apd = apd_next )
  {
    apd_next = apd->next;
    MY_DISPOSE( apd );
  }

  /* Some freaking globals */
  fprintf( stdout, "Globals.\n" );
  MY_DISPOSE( ranged_target_name );

}   /* cleanup memory */

/* End $RCSfile: cleanup.c,v $ */