ackmud/
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/
ackmud/player/s/
ackmud/player/z/
#include <sys/types.h>
#include <sys/time.h>

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


#include "ssm.h"

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

#ifdef IMC
#include "imc-mercbase.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 songs
 * o IMC
 *
 */

/* From note.c: */
#if 0
extern NOTE_DATA *note_list;
extern NOTE_DATA *idea_list;
extern NOTE_DATA *penalty_list;
extern NOTE_DATA *news_list;
extern NOTE_DATA *changes_list;
#endif

/* From ban.c: */

extern BAN_DATA *first_ban;

#if 0
/* From bounty.c: */

extern BOUNTY_DATA *bounty_list;
#endif

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("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_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);

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

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

}

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

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

  /* exit[i] == old_exit[i], so don't walk it twice */

  for (ed = r->first_exdesc; ed; ed = ed->next)
    walk_extra_descr_data(ed);
/*  for ( reset = r->first_room_reset; reset; reset = reset->next )
    walk_reset_data( reset->data );    */
  touch(r->name);
  touch(r->description);
  touch(r->auto_message);
}


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 0
static void walk_song_data(struct song_data *s)
{
  int i;

  touch(s->name);
  touch(s->group);

  for (i = 0; i < s->lines; i++)
    touch(s->lyrics[i]);
}

#endif

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

#if 0
static void walk_bounty_data(BOUNTY_DATA *b)
{
  touch(b->name);
  touch(b->by);
}
#endif


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);
#if 0
  walk_notelist(idea_list);
  walk_notelist(penalty_list);
  walk_notelist(news_list);
  walk_notelist(changes_list);
#endif
}
#if 0
static void walk_songs(void)
{
  int i;

  for (i = 0; i < MAX_SONGS; i++)
    if (song_table[i].name)
      walk_song_data(&song_table[i]);
}
#endif

static void walk_bans(void)
{
  BAN_DATA *b;

  for (b = first_ban; b; b = b->next)
    walk_ban_data(b);
}
#if 0
static void walk_bounties(void)
{
  BOUNTY_DATA *b;

  for (b=bounty_list; b; b=b->next)
    walk_bounty_data(b);
}
#endif

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 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( );
  
#if 0
   walk_songs();
  walk_bounties();
#endif


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

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