ackmud/area/boards/
ackmud/area/imc/
ackmud/npcs/a/
ackmud/npcs/c/
ackmud/npcs/d/
ackmud/npcs/e/
ackmud/npcs/f/
ackmud/npcs/h/
ackmud/npcs/i/
ackmud/npcs/k/
ackmud/npcs/l/
ackmud/npcs/n/
ackmud/npcs/o/
ackmud/npcs/p/
ackmud/npcs/r/
ackmud/npcs/s/
ackmud/npcs/w/
ackmud/player/c/
/***************************************************************************
 *  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              *
 *                                                                         *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.                                               *
 *                                                                         *
 *       _/          _/_/_/     _/    _/     _/    ACK! MUD is modified    *
 *      _/_/        _/          _/  _/       _/    Merc2.0/2.1/2.2 code    *
 *     _/  _/      _/           _/_/         _/    (c)Stephen Zepp 1998    *
 *    _/_/_/_/      _/          _/  _/             Version #: 4.3          *
 *   _/      _/      _/_/_/     _/    _/     _/                            *
 *                                                                         *
 *                        http://ackmud.nuc.net/                           *
 *                        zenithar@ackmud.nuc.net                          *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/

#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"

#ifdef DEBUG_MONEY
#ifndef DEC_MONEY_H
#include "money.h"
#endif
#endif


#include "ssm.h"

/* for IMC2 0.6 or higher (<0.6 will need tweaking) */
#define IMC

#ifdef IMC
#include "imc-mercbase.h"
#include "icec-mercbase.h"
#include "imc.h"
#endif

/*  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 mob_index hash table
 * o obj_index hash table
 * o room_index hash table
 * o socials table
 * o helps
 * o areas
 * o notes/ideas/etc
 * o IMC
 *
 */



/* From ban.c: */

extern BAN_DATA *first_ban;


extern MOB_INDEX_DATA *        mob_index_hash          [MAX_KEY_HASH];
extern OBJ_INDEX_DATA *        obj_index_hash          [MAX_KEY_HASH];
extern ROOM_INDEX_DATA *       room_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_mprog_data(MPROG_DATA * prog)
{
  if (!prog)
    return;

  touch(prog->arglist);
  touch(prog->comlist);
  touch(prog->filename);

}
static void walk_mprog_act_data(MPROG_ACT_LIST * act)
{
  if (!act)
    return;

  touch(act->buf);

}


static void walk_mob_index_data(MOB_INDEX_DATA * m)
{
  MPROG_DATA	*mobprog;
  if (!m)
    return;

  touch(m->player_name);
  touch(m->short_descr);
  touch(m->long_descr);
  touch(m->description);
  touch(m->target);
  for( mobprog = m->first_mprog; mobprog; mobprog = mobprog->next )
    walk_mprog_data( mobprog );

}

static void walk_ngroup_data(NPC_GROUP_DATA * ngrp)
{
  if (!ngrp)
    return;

  touch( ngrp->enemies );
  touch( ngrp->last_fighting );
  touch( ngrp->wants );
  touch( ngrp->needs );
}

static void walk_ngroups( void )
{
  NPC_GROUP_DATA * ngroup;

  for ( ngroup = first_npc_group;
        ngroup;
        ngroup = ngroup->next )
  {
    walk_ngroup_data( ngroup );
  }
}

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->immskll);
  touch(p->host);
  touch(p->who_name);
  touch(p->header);
  touch(p->message );
  touch(p->lastlogin);
  touch(p->load_msg);


  touch(p->rreply);
  touch(p->rreply_name);
  touch(p->ice_listen);
  for ( i = 0; i < MAX_IGNORES; i++ )
    touch( p->ignore_list[i]);
         
  for (i = 0; i < MAX_ALIASES; i++)
  {
    touch(p->alias[i]);
    touch(p->alias_name[i]);
  }
  for ( i = 0; i < 5 ; i++ )
  {
    touch( p->pedit_string[i] );
  }
  touch( p->pedit_state );
  touch( p->email_address );
  touch( p->assist_msg );
}
static void walk_shield_data(MAGIC_SHIELD * shield)
{
  if (!shield)
    return;

  touch(shield->name);
  touch(shield->absorb_message_room);
  touch(shield->absorb_message_victim);
  touch(shield->absorb_message_self);
  touch(shield->wearoff_room);
  touch(shield->wearoff_self);

}

static void walk_note_data(NOTE_DATA * note)
{
  if (!note)
    return;

  touch(note->sender);
  touch(note->date);
  touch(note->to_list);
  touch(note->subject);
  touch(note->text);
}
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_shieldlist(MAGIC_SHIELD * shield)
{
  for (; shield; shield = shield->next)
    walk_shield_data(shield);
}

static void walk_mprog_act(MPROG_ACT_LIST *act)
{
  for (; act; act = act->next)
    walk_mprog_act_data(act);
}

void walk_notelist(NOTE_DATA * pnote)
{
  for (; pnote; pnote = pnote->next)
    walk_note_data(pnote);
}

static void walk_char_data(CHAR_DATA * ch)
{
  if (!ch)
    return;

  walk_notelist(ch->pnote);
  walk_pcdata(ch->pcdata);
  walk_shieldlist( ch->first_shield );
  walk_mprog_act( ch->first_mpact );

  touch(ch->name);
  touch(ch->short_descr);
  touch(ch->long_descr);
  touch(ch->long_descr_orig);
  touch(ch->description);
  touch(ch->prompt);
  touch(ch->old_prompt);
  touch(ch->searching);
  touch(ch->target);
#ifdef DEBUG_MONEY
  if ( ch->money )
    touch( ch->money->money_key );
  if ( ch->bank_money )
    touch( ch->bank_money->money_key );
#endif


}

static void walk_extra_descr_data(EXTRA_DESCR_DATA * ed)
{
  if (!ed)
    return;

  touch(ed->keyword);
  touch(ed->description);
}

static void walk_obj_index_data(OBJ_INDEX_DATA * o)
{
  EXTRA_DESCR_DATA *ed;

  if (!o)
    return;

  for (ed = o->first_exdesc; ed; ed = ed->next)
    walk_extra_descr_data(ed);

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


static void walk_obj_data(OBJ_DATA * o)
{
  EXTRA_DESCR_DATA *ed;

  if (!o)
    return;

  for (ed = o->first_exdesc; ed; ed = ed->next)
    walk_extra_descr_data(ed);

  touch(o->owner);
  touch(o->name);
  touch(o->short_descr);
  touch(o->description);
#ifdef DEBUG_MONEY
  if ( o->money )
    touch( o->money->money_key );
#endif

  
}

static void walk_exit_data(EXIT_DATA * e)
{
  if (!e)
    return;

  touch(e->keyword);
  touch(e->description);
}

static void walk_reset_data(RESET_DATA * r)
{
  if (!r)
    return;

  touch(r->notes);
  touch(r->auto_message);
}

static void walk_area_data(AREA_DATA * ad)
{

  RESET_DATA *reset;
  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 */
  touch(ad->level_label); /* spec - missed strings */
  touch(ad->reset_msg);
  for ( reset = ad->first_reset; reset; reset = reset->next )
    walk_reset_data( reset );

}

/* spec - for the new rulers stuff */
static void walk_ruler_data(RULER_DATA *ruler)
{
  if (!ruler)
    return;
  touch(ruler->name);
  touch(ruler->affiliation_name);
  touch(ruler->keywords);
}

static void walk_room_index_data(ROOM_INDEX_DATA * r)
{
  int i;
  EXTRA_DESCR_DATA *ed;
/*  BUILD_DATA_LIST *reset;  */
  if (!r)
    return;

  for (i = 0; i < 6; i++)
    walk_exit_data(r->exit[i]);


  for (ed = r->first_exdesc; ed; ed = ed->next)
    walk_extra_descr_data(ed);
  touch(r->name);
  touch(r->description);
  touch(r->auto_message);
#ifdef DEBUG_MONEY
  touch( r->treasure->money_key );
#endif
}


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);
}



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



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);
}

static void walk_areas(void)
{
  AREA_DATA *ad;

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

/* spec- more rulers stuff */
static void walk_rulers(void)
{
  RULER_LIST *r;

  for (r=first_ruler_list; r; r=r->next)
    walk_ruler_data(r->this_one);
}

static void walk_mob_indexes(void)
{
  MOB_INDEX_DATA *m;
  int i;

  for (i = 0; i < MAX_KEY_HASH; i++)
    for (m = mob_index_hash[i]; m; m = m->next)
      walk_mob_index_data(m);
}

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_room_indexes(void)
{
  ROOM_INDEX_DATA *r;
  int i;

  for (i = 0; i < MAX_KEY_HASH; i++)
    for (r = room_index_hash[i]; r; r = r->next)
      walk_room_index_data(r);
}


static void walk_notes(void)
{
  walk_notelist(first_note);
}

static void walk_bans(void)
{
  BAN_DATA *b;

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

static void walk_mark_data(MARK_DATA * m)
{
  if (!m)
    return;

  touch(m->message);
  touch(m->author);
}

void walk_marklist( void )
{
  MARK_LIST_MEMBER	*tmark;
  for (tmark = first_mark_list; tmark; tmark = tmark->next)
    walk_mark_data(tmark->mark);
}

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_councils( void )
{
  sh_int	index;
  extern COUNCIL_DATA super_councils[MAX_SUPER];
 
  for (index = 0; index < MAX_SUPER; index++)
    touch(super_councils[index].council_name);
}
void walk_sysdata( void )
{
  sh_int looper;
  touch( sysdata.playtesters );
  for ( looper = 0; looper < MAX_NUM_IMMS; looper++ )
   touch( sysdata.imms[looper].this_string);
}


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_mob_indexes();
  walk_obj_indexes();
  walk_room_indexes();
  walk_notes();
  walk_marklist( );
  walk_councils();
  walk_boards();
  walk_rulers();
  walk_brands( );
  walk_sysdata( );
  walk_ngroups( );  

#ifdef IMC
  /* IMC2 string checking */
  imc_markstrings(touch);
#endif

#ifdef ICEC_MERC_H
  icec_markstrings(touch);
#endif

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