lurf/area/
lurf/build/testing/
lurf/log/
lurf/player/
lurf/player/backup/
/**************************************************************************
   mkwSys.c version 2.01
   *************************************************************************
   Brought to you by Michael K. Weise               http://home.att.net/~mkw
                     (a.k.a. Mizadil)                     mailto:mkw@att.net
   *************************************************************************
   Provides an improved, more informative memory command.
   Automatically sets string space size, doing away with the need to edit 
   MAX_STRING and recompile when adding areas.
   Provides several very convenient functions for use throughout your code,
   including chprintf(), logf(), strswitch() and my subcommand interpreter, 
   vinterpret(). See my comments throughout this file for information on 
   other features.
   *************************************************************************
   *************************************************************************
   This code was written and is copyright (c) 1998 by Michael K. Weise.
   Portions of this code are derived from code included with ROM 2.4b4a,
   and are therefore subject to the ROM, MERC and Diku license agreements.
   Released by to the public for non-commercial use on the sole condition
   that this comment block not be removed or altered in any way.
   It may be released as part of a derivative work on the conditions that 
   this comment block remain unaltered in the source and that proper credit
   be given to Michael K. Weise in the release's main licence or readme file.
   Crediting the author in a help entry is appreciated, but not required.
   *************************************************************************
   This code is designed to work in conjunction with MERC and its derivatives.
   It has been extensively tested with ROM 2.4b4a; other code bases may 
   require slight changes to the code. 
   MERC and ROM are copyrighted by their respective authors; see the comment 
   block in your merc.h for more information.
   *************************************************************************
   Any bugs in or suggested improvements to the code in this file should be 
   reported to mkw@att.net. For issues relating to learing C/C++, see my web 
   page. For issues relating to the ROM/MERC/Diku code in general, see 
   Garry's FAQ at http://www.hypercube.org/tess/rom/faq.
   *************************************************************************/
#include <glib.h>

#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <stdarg.h>
#include <merc.h>
//#include <db.h>
#include <recycle.h>
#include <memory.h>

const size_t    rgSizeList      [MAX_MEM_LIST]
                        = { 16, 32, 64, 128, 256, 1024, 2048, 4096, 8192, 16384,
 32768-64 };

/*********************************************************
 *  imports
 */
extern void boot_fail args((char* module_name));
extern char *		string_space;
extern int 		get_mobile_count(char * argument);
extern	GSList	*object_free;
extern	CHAR_DATA	*char_free;
extern  GSList *descriptor_free;
extern	PC_DATA		*pcdata_free;
extern  AFFECT_DATA	*affect_free;
//extern	NOTE_DATA	*note_list;



/*********************************************************
 *  locals
 */

int		has_system_auth( CHAR_DATA* ch );
extern void *		rgFreeList	[MAX_MEM_LIST];



/****************************************************************
 * Implementation section
 */

const char ver_mkwSys[]="mkwSys Version 2.01";

void*	 rgFreeList	[MAX_MEM_LIST];

unsigned long nAllocGP[MAX_MEM_LIST] = { 0,0,0,0,0,0,0,0,0,0,0};

int		nPermBlocks = 0;



int has_system_auth( CHAR_DATA* ch )
{
	if( get_trust( ch ) < LEVEL_HIGHJUDGE )
	{
		send_to_char( "You are not authorized to issue system commands.\n\r", ch );
		return FALSE;
	}
	else
		return TRUE;
}

#define IMP_COUNTER( type, start, px) \
  int px##type() { type * p = start; int n = 0; while( p!=NULL ) { p= p->next; n++; } return n; }
  

#define IMP_LIST_COUNTERS( type, prefix ) \
		IMP_COUNTER( type, prefix##list, n )	IMP_COUNTER( type, prefix##free, f )
  

			// these object types have no global list
IMP_COUNTER ( PC_DATA, pcdata_free, f)
IMP_COUNTER ( AFFECT_DATA, affect_free, f)

			// these do
IMP_LIST_COUNTERS ( CHAR_DATA, char_ );

#ifdef MPROGS_INSTALLED
IMP_COUNTER ( MPROG_CODE, mprog_list, n );
//IMP_LIST_COUNTER ( MPROG_LIST, ??? );
			// not currently implemented 
			// (There is no global list of MPROG_LISTs to count from)
#endif

int nNOTE_DATA()
{	
	/*
	NOTE_DATA* p; int n = 0; 
	for( p=note_list;p!=NULL; p=p->next) n++; 
	return n; 
	*/
	return 0;
}


#define rpt( name, n, obj ) chprintf( ch, "%5d %-14s *%4d Bytes =%6d kB\n\r", \
	                                 n, name, sizeof(obj), (n) * sizeof(obj)/1024 )
			// report on an object type

#define rpt_dy( name, type ) { int n= n##type(); rpt( name, n, type ); }
			// report object with dynamic counting of list -
			// calls rpt() without evaluating n twice 

#define rptsd( st, sz )	chprintf( ch, "%-34s %5d kB\n\r", st, sz )
			// report string and decimal

#define rptdsd(n,st,sz)	chprintf( ch, "%5d %-28s %5d kB\n\r", n, st, sz )
			// report decimal, string, decimal

const char separator[] = "-------------------------------------------\n\r";

void do_memory_perms( CHAR_DATA *ch, char* argument )
{
	int i;
	chwrite( ch, separator );
	chwrite( ch, "Permanent memory objects in use\n\r");
	chwrite( ch, separator );
	rpt_dy( "Characters", CHAR_DATA );
	rpt( "PCs", nCHAR_DATA() - get_mobile_count(argument) /* should be an accurate shortcut */, PC_DATA ); 
	rpt( "Descriptors", g_slist_length(descriptor_list), DESCRIPTOR_DATA);
	rpt( "Mob Prototypes", top_mob_index, MOB_INDEX_DATA );
	rpt( "Obj Prototypes", top_obj_index, OBJ_INDEX_DATA);
	rpt( "Objects", g_slist_length(object_list), OBJ_DATA);
	rpt( "Extra Descs", top_ed, EXTRA_DESCR_DATA );
	rpt( "Affects", top_affect, AFFECT_DATA );
	rpt( "Rooms", top_room, ROOM_INDEX_DATA );
	rpt( "Exits", top_exit, EXIT_DATA );
	rpt( "Shops", top_shop, SHOP_DATA );
	rpt( "Areas", top_area, AREA_DATA );
	rpt( "Resets", top_reset, RESET_DATA );
	rpt( "Help entries", top_help, HELP_DATA );
	rpt_dy( "Notes", NOTE_DATA);
	rpt( "Socials", social_count, struct social_type );
#ifdef MPROGS_INSTALLED
	rpt_dy( "Mob progs", MPROG_CODE )
#endif
	for( i= 0; i<MAX_MEM_LIST; i++)
#ifndef SHOW_ALL_RGSIZES
	   if( nAllocGP[i] )
#endif
			chprintf( ch, "%5d GP blocks of  %6d Bytes =%6d kB\n\r", 
					nAllocGP[i], rgSizeList[i], nAllocGP[i] * rgSizeList[i] / 1024);
	chwrite( ch, separator );
}


#define rptf( name, type ) { int n= f##type(); rpt( name, n, type ); }

void do_memory_freelists( CHAR_DATA *ch, char* argument )
{
	int i;
	chwrite( ch, separator );
	chwrite( ch, "Memory objects waiting to be recycled\n\r");
	chwrite( ch, separator );
	rptf( "Characters", CHAR_DATA );
	rptf( "PCs", PC_DATA ); 
	rpt( "Descriptors", g_slist_length(descriptor_list), DESCRIPTOR_DATA);
	rptf( "Affects", AFFECT_DATA );
	rpt( "Objects", g_slist_length(object_list), OBJ_DATA);
	
	for( i= 0; i<MAX_MEM_LIST; i++)
#ifndef SHOW_ALL_RGSIZES
	   if( rgFreeList[i] )
#endif
	   {
		void* p;
		int n = 0;
		for(p= rgFreeList[i]; p != NULL; p= * ((void **) p ) )
			n++;
		chprintf( ch, "%5d GP blocks of  %6d Bytes =%6d kB\n\r", 
			n, rgSizeList[i], n * rgSizeList[i] / 1024);
	   }
	chwrite( ch, separator );
}


void do_memory_formats( CHAR_DATA *ch, char* argument )
{
	chwrite( ch, separator );
    chprintf( ch, "Old format mobs: %d\n\rOld format objects: %d\n\r", 
		     top_mob_index, top_obj_index); 
	chwrite( ch, separator );
}

#undef rpt
#undef rpt_dy
#undef rptsd
#undef rptdsd
	/* Those macros are not for general use */

void do_memory_help( CHAR_DATA *ch, char *argument )
{
	chwrite(ch, ver_mkwSys );
	chwrite(ch, " copyright (c) 1998 Michael K. Weise\n\r"
				"See home.att.net/~mkw/mudframe.html for more information\n\n\r"
				"usage: newmem <command>\n\r\ravailable commands:\n\r"
				"heap                Report heap memory allocated by the memory manager\n\r"
				"perms               Report managed memory objects in use by other modules\n\r"
				"freelists           Report memory objects waiting to be recycled\n\r"
				"formats             Report old format prototypes\n\r"
				"?                   This message\n\r"
				 );
}


void do_newmem( CHAR_DATA *ch, char *argument )
{
	vinterpret( ch, argument, 
				"perms", do_memory_perms,
				"freelists", do_memory_freelists,
				"formats", do_memory_formats,
				NULL, do_memory_help );
}


int strswitch( const char* arg, ... )
{
	int i = 0;
	char* p;
	va_list caselist;
	if( arg[0] )
	{
		va_start( caselist, arg );
		while( (p = va_arg( caselist, char* )) != NULL )
		{
			i++;
			if( !str_prefix( arg, p ) )
				return i;
		}
	}
	return 0;
}


void vinterpret( CHAR_DATA *ch, char *argument, ... )
{
	char arg[MAX_INPUT_LENGTH];
	char* iStr;
	DO_FUN *iFun;
	va_list caselist;
	va_start( caselist, argument );
	argument= one_argument( argument, arg );
	do 
	{
		iStr = va_arg( caselist, char* );
		iFun = va_arg( caselist, DO_FUN* );
	} 
	while( iStr != NULL && ( !arg[0] || str_prefix( arg, iStr ) ) );
	if( iFun != NULL )
		(*iFun)( ch, argument );
}


size_t rgSize_lookup( size_t size )
{
    int iList;
    size += sizeof( int );	// room needed for integrity marker

	for ( iList = 0; iList < MAX_MEM_LIST; iList++ )
    {
        if ( size <= rgSizeList[iList] )
            return rgSizeList[iList] - sizeof( int );
    }
    return 0; // size won't fit into any alloc_mem() block
}


/*
 * Give a GP block back to the memory manager for recycling.
 */
void free_mem( void *pMem, size_t sMem )
{
    int iList;

#ifdef MAGIC_CHECKING
    int *magic;
  
 	pMem = (void*) (((char*)pMem) - sizeof (*magic));	
    magic = (int *) pMem;
  
    if (*magic != MAGIC_NUM)
    {
        bug("Attempt to recyle invalid memory of size %d.",sMem);
        bug((char*) pMem + sizeof(*magic),0);
	    abort();
        return;
    }

    *magic = 0;
    sMem += sizeof(*magic);
#endif

    for ( iList = 0; iList < MAX_MEM_LIST; iList++ )
    {
        if ( sMem <= rgSizeList[iList] )
            break;
    }

    if ( iList == MAX_MEM_LIST )
    {
        bug( "Free_mem: size %d too large.", sMem );
        abort();
    }

    * ((void **) pMem) = rgFreeList[iList];
    rgFreeList[iList]  = pMem;

    return;
}

void check_string( void *pMem, size_t sMem )
{
    int *magic;
  
 	pMem = (void*) (((char*)pMem) - sizeof (*magic));	
    magic = (int *) pMem;
  
    if (*magic != MAGIC_NUM)
    {
        bug("Invalid memory of size %d.",sMem);
        bug((char*) pMem + sizeof(*magic),0);
	    logchan("Invalid memory string caught! Check the Bug logs!",NULL,NULL,WIZ_DEBUG,0,LEVEL_JUDGE);
		return;
    }

    return;
}




/* 
 * All ANSI C compilers aught to have stdarg.h.
 * If not, #include <varargs.h>
 * and implement logf() in traditional C style 
 */
int logf( const char *format, ... )
{
	va_list arglist;
	char *strtime;
	int status;
	va_start( arglist, format );
    strtime = ctime( &current_time );
    strtime[strlen(strtime)-1] = '\0';
    fprintf( stderr, "%s :: ", strtime );
#ifdef DOUBLE_LOGGING
	fprintf( stdout, "%s :: ", strtime );
	vfprintf( stdout, format, arglist );
    fprintf( stdout, "\n" );
	fflush( stdout );
#endif
	status = vfprintf( stderr, format, arglist );
	va_end( arglist );
    fprintf( stderr, "\n" );
	fflush( stderr );
	return status;
}


int chprintf( CHAR_DATA* ch, const char *format, ... )
{
	static char buf[MAX_STRING_LENGTH+1];
	va_list arglist;
	int nChars= 0;
	va_start( arglist, format );
	if ( format != NULL && format[0] && ch->desc != NULL )
	{
		nChars = vsprintf( buf, format, arglist );
		assert( nChars <= MAX_STRING_LENGTH );
		write_to_buffer( ch->desc, buf, nChars );
	}
	va_end( arglist );
	return nChars;
}