player/a/
player/b/
player/c/
player/d/
player/e/
player/f/
player/g/
player/i/
player/j/
player/k/
player/m/
player/n/
player/r/
player/s/
player/v/
player/w/
player/x/
player/z/
player_fst/e/
player_fst/f/
player_fst/h/
player_fst/i/
player_fst/j/
player_fst/n/
player_fst/o/
player_fst/p/
player_fst/player/a/
player_fst/player/b/
player_fst/player/c/
player_fst/player/d/
player_fst/player/e/
player_fst/player/f/
player_fst/player/g/
player_fst/player/j/
player_fst/player/k/
player_fst/player/m/
player_fst/player/n/
player_fst/player/r/
player_fst/player/s/
player_fst/player/v/
player_fst/player/w/
player_fst/player/x/
player_fst/player/z/
player_fst/u/
player_fst/v/
player_fst/w/
player_fst/x/
/*~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
 ~  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        ~
 ~  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   ~
 ~                                                                         ~
 ~  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          ~
 ~  Chastain, Michael Quan, and Mitchell Tse.                              ~
 ~                                                                         ~
 ~  Ack 2.2 improvements copyright (C) 1994 by Stephen Dooley              ~
 ~  ACK!MUD is modified Merc2.0/2.1/2.2 code (c)Stephen Zepp 1998 Ver: 4.3 ~
 ~                                                                         ~
 ~  In order to use any part of this  PA  Diku Mud, you must comply with   ~
 ~  both the original Diku license in 'license.doc' as well the Merc       ~
 ~  license in 'license.txt', and the Ack!Mud license in 'ack_license.txt'.~
 ~  In particular, you may not remove any of these copyright notices.      ~
 ~                                                                         ~
 ~           _______      _____                                            ~
 ~          /  __  /\    / ___ \       222222        PA_MUD by Amnon Kruvi ~
 ~         /______/ /   / /___\ \            2       PA_MUD is modified    ~
 ~        / _______/   / _______ \           2       Ack!Mud, v4.3         ~
 ~       /_/          /_/       \_\        2                               ~
 ~                                      2                                  ~
 ~                                     2222222                             ~
 ~                                                                         ~
 ~                                                                         ~
 ~   Years of work have been invested to create DIKU, Merc, Ack and PA.    ~
 ~   Please show your respect by following the licenses, and issuing       ~
 ~   credits where due.                                                    ~
 ~                                                                         ~
 ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-*/

#include <sys/types.h>
#include <sys/time.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "ack.h"
#include "tables.h"

#include "ssm.h"

/*  String checker, Spectrum 11/96
 *
 *  Basic idea is to walk through all the strings we know about, and mark them
 *  as referenced. Then we check for strings that have a reference count thats
 *  different from ptr->usage and log them
 */

/*
 * Things which are walked (anything else must be touched from these):
 *
 * o char_list
 * o descriptor_list
 * o object_list
 * o obj_index hash table
 * o socials table
 * o helps
 * o areas
 * o notes/ideas/etc
 */



extern char * quote_table[MAX_QUOTE];

/* From ban.c: */

extern BAN_DATA *first_ban;


extern OBJ_INDEX_DATA *        obj_index_hash          [MAX_KEY_HASH];

/* Main code */

static void touch(char *str)
{
  BufEntry *p;

  if (!str)
    return;

  if (str < string_space || str > top_string)
    return;			/* not in string space */

  p = (BufEntry *) (str - HEADER_SIZE);
  p->ref++;
}

static void clear(void)
{
  /* Set all reference counts to 0 */

  BufEntry *p;

  for (p = ssm_buf_head; p; p = p->next)
    p->ref = 0;
}

static BufEntry *dump_ptr[2];

static long dump(void)
{
  /* Dump strings that have ref!=usage */

  FILE *dumpf;
  BufEntry *p;
  long count = 0;

  fclose(fpReserve);
  dumpf = fopen("../reports/leaks.dmp", "w");

  for (p = ssm_buf_head; p; p = p->next)
  {
    if (p->usage > 0 && p->usage != p->ref)
    {
      /* things to ignore:
       * the common <%hhp %mm %vmv> prompt string
       * a '$' (from socials)
       */

      if (!str_cmp(p->buf, "<%hhp %mm %vmv> ") ||
	  !str_cmp(p->buf, "$"))
	continue;

      fprintf(dumpf, "usage %2d/%2d, caller %s, string %s\n",
	      p->ref,
	      p->usage,
	      p->caller,
	      p->buf);
      count += abs(p->usage - p->ref);
    }
    dump_ptr[0]=dump_ptr[1];
    dump_ptr[1]=p;
  }

  fclose(dumpf);
  fpReserve = fopen(NULL_FILE, "r");

  return count;
}

static void walk_web ()
{
	touch(history1);
	touch(history2);
	touch(history3);
	touch(history4);
	touch(history5);
	touch(history6);
	touch(history7);
	touch(history8);
	touch(history9);
	touch(history10);
	touch(web_data.last_killed_in_pit);
	touch(web_data.last_kills_in_pit);
	touch(web_data.highest_ranking_player);
	touch(web_data.newest_player);
	return;
}
static void walk_queue_data(QUEUE_DATA * q)
{
  if (!q)
    return;

  touch(q->command);
  walk_queue_data(q->next);
}
static void walk_pcdata(PC_DATA * p)
{
  int i;

  if (!p)
    return;

  touch(p->pwd);
  touch(p->bamfin);
  touch(p->bamfout);
  touch(p->title);
  touch(p->room_enter);
  touch(p->room_exit);
  touch(p->host);
  touch(p->who_name);
  touch(p->header);
  touch(p->message );
  touch(p->lastlogin);
  touch(p->load_msg);

  for ( i = 0; i < MAX_IGNORES; i++ )
    touch( p->ignore_list[i]);
         
  for ( i = 0; i < 5 ; i++ )
  {
    touch( p->pedit_string[i] );
  }
  touch( p->pedit_state );
  touch( p->email_address );
  walk_queue_data(p->queue);
}

static void walk_brand_data(BRAND_DATA * brand)
{
  if (!brand)
    return;

  touch(brand->branded);
  touch(brand->branded_by);
  touch(brand->dt_stamp);
  touch(brand->message);
  touch(brand->priority);
}
static void walk_brands( void )
{
  BRAND_DATA *	this_brand;
  DL_LIST *	brands;
  for (brands = first_brand ; brands; brands = brands->next)
  {
    this_brand = brands->this_one;
    walk_brand_data(this_brand);
  }
}

static void walk_char_data(CHAR_DATA * ch)
{
  int i;

  if (!ch)
    return;

  walk_pcdata(ch->pcdata);

  touch(ch->name);
  touch(ch->prompt);
  touch(ch->old_prompt);
  touch(ch->last_tell);
  for ( i = 0;i < 5;i++ )
  {
	touch( ch->alias[i]);
	touch( ch->alias_command[i]);
  }

}

static void walk_obj_index_data(OBJ_INDEX_DATA * o)
{
  if (!o)
    return;

  touch(o->name);
  touch(o->short_descr);
  touch(o->description);
  touch(o->owner);
  touch(o->image);
}


static void walk_obj_data(OBJ_DATA * o)
{
  if (!o)
    return;

  touch(o->owner);
  touch(o->name);
  touch(o->short_descr);
  touch(o->description);
}

static void walk_area_data(AREA_DATA * ad)
{

  if (!ad)
    return;

  touch(ad->filename);
  touch(ad->name);
  touch(ad->owner);
  touch(ad->can_read);
  touch(ad->can_write);
  touch(ad->keyword);    /* spec- missed strings */
}

static void walk_social_type(struct social_type *s)
{


  if (!s)
    return;
  touch( s->name );
  touch(s->char_no_arg);
  touch(s->others_no_arg);
  touch(s->char_found);
  touch(s->others_found);
  touch(s->vict_found);
  touch(s->char_auto);
  touch(s->others_auto);
}

static void walk_help_data(HELP_DATA * h)
{
  if (!h)
    return;

  touch(h->keyword);
  touch(h->text);
}

static void walk_descriptor_data(DESCRIPTOR_DATA * d)
{
  if (!d)
    return;

  touch(d->host);
  if ( d->connected != CON_PLAYING )
	walk_char_data (d->character);
}



static void walk_ban_data(BAN_DATA * b)
{
  touch(b->name);
  touch( b->banned_by);
  touch( b->note);
}



static void walk_socials(void)
{
  extern int maxSocial;
  int i;

  for (i = 0; i < maxSocial; i++)
    walk_social_type(&social_table[i]);
}

static void walk_helps(void)
{
  HELP_DATA *h;

  for (h = first_help; h; h = h->next)
    walk_help_data(h);
}

static void walk_chars(void)
{
  CHAR_DATA *ch;

  for (ch = first_char; ch; ch = ch->next)
    walk_char_data(ch);
}

static void walk_descriptors(void)
{
  DESCRIPTOR_DATA *d;

  for (d = first_desc; d; d = d->next)
    walk_descriptor_data(d);
}

static void walk_objects(void)
{
  OBJ_DATA *o;

  for (o = first_obj; o; o = o->next)
    walk_obj_data(o);
  walk_obj_data(vehicle_weapon);
}

static void walk_areas(void)
{
  AREA_DATA *ad;

  for (ad = first_area; ad; ad = ad->next)
    walk_area_data(ad);
}

static void walk_obj_indexes(void)
{
  OBJ_INDEX_DATA *o;
  int i;

  for (i = 0; i < MAX_KEY_HASH; i++)
    for (o = obj_index_hash[i]; o; o = o->next)
      walk_obj_index_data(o);
}

static void walk_bans(void)
{
  BAN_DATA *b;

  for (b = first_ban; b; b = b->next)
    walk_ban_data(b);
}

static void walk_message_data(MESSAGE_DATA * m)
{
  if (!m)
    return;

  touch(m->message);
  touch(m->author);
  touch(m->title );
}
void walk_messages( MESSAGE_DATA * m )
{
  for( ; m ; m = m->next )
    walk_message_data( m );
}
void walk_boards( void )
{
  BOARD_DATA	*board;
  extern BOARD_DATA *first_board;
  for (board = first_board; board; board = board->next)
    walk_messages(board->first_message);
}

void walk_sysdata( void )
{
  sh_int looper;
  touch( sysdata.playtesters );
  for ( looper = 0; looper < 5; looper++ )
   touch( sysdata.imms[looper].this_string);
}

void walk_quotes( void )
{
  sh_int looper;
  for ( looper = 0; looper < MAX_QUOTE; looper++ )
   touch( quote_table[looper] );
}

static void walk_disable_data(DISABLED_DATA * disable)
{
  if (!disable)
    return;

  touch(disable->disabled_by);
}

void walk_disablelist(void)
{
  DISABLED_DATA *disable;

  for (disable = disabled_first; disable; disable = disable->next)
  {
    walk_disable_data(disable);
  }
}

void walk_alliances(void)
{
  int i;
  for ( i=0;i<MAX_ALLIANCE;i++ )
  {
	if ( alliance_table[i].name == NULL )
		break;
	touch( alliance_table[i].name );
	touch( alliance_table[i].leader );
	touch( alliance_table[i].history );
  }
}
void walk_scores(void)
{
  int i;
  for ( i=0;i<100;i++ )
  {
	touch( score_table[i].name );
	touch( score_table[i].killedby );
  }
  for ( i=0;i<30;i++ )
	touch( rank_table[i].name );
}
void walk_multiplay(void)
{
  int i;
  for ( i=0;i<30;i++ )
  {
	touch(multiplay_table[i].name);
	touch(multiplay_table[i].host);
  }
}
void walk_build_table(void)
{
  int i;
  for ( i=0;i<MAX_BUILDING;i++ )
  {
	touch(build_table[i].name);
	touch(build_table[i].desc);
	touch(build_table[i].symbol);
	touch(build_help_table[i].help);
  }
}
void walk_buildings(void)
{
  BUILDING_DATA *bld;
  for ( bld = first_building;bld;bld = bld->next )
  {
	touch( bld->owned );
	touch( bld->name );
	touch( bld->attacker );
  }
}
void walk_vehicles(void)
{
  VEHICLE_DATA *vhc;
  for ( vhc = first_vehicle;vhc;vhc = vhc->next )
  {
	touch( vhc->name );
	touch( vhc->desc );
  }
}
void do_scheck(CHAR_DATA * ch, char *argument)
{
  char buf[MAX_STRING_LENGTH];
  extern bool disable_timer_abort;
  disable_timer_abort = TRUE;
  clear();

  walk_socials();
  walk_helps();
  walk_chars();
  walk_descriptors();
  walk_objects();
  walk_areas();
  walk_bans();


  walk_obj_indexes();
  walk_boards();
  walk_brands( );
  walk_sysdata( );
  walk_quotes( );
  walk_disablelist( );
  walk_buildings( );
  walk_vehicles( );
  walk_scores( );
  walk_multiplay( );
  walk_build_table( );
  walk_alliances( );
  walk_web ();

  sprintf(buf, "%ld leaks dumped to leaks.dmp\n\r",
	  dump());
  send_to_char(buf, ch);
  disable_timer_abort = FALSE;
}