/* mem_header.h
 *
 * Written by David Allen, s2mdalle@titan.vcu.edu 
 * http://opop.nols.com/
 *
 * This file is released under the terms of the GNU General Public License.
 * See COPYING or http://www.gnu.org/ for more details.
 *
 * This is a simple set of macros to watch memory allocation/deallocation
 * on the part of my calls to gtkeyboard.  Most of it will never even happen
 * unless GTKEYBOARD_MEMORY_DEBUGGING is defined.  If it is defined, it
 * will count the memory allocated and freed.  If it isn't defined, then
 * the memory calls will be synonyms for their normal calls.  (e.g.
 * g_free_() -> g_free() and so on.)
 *
 * Since these are also only included in YOUR calls, any memory that 
 * g_mem_profile() reports as unfreed should probably be GTK+'s fault.
 *
 * WARNING:  Because each memory alloc statement gets expanded to more than
 * one statement, don't do things like if(foo) baz = g_strdup(foo); but
 * rather something like if(foo){  baz = g_strdup(foo); } or you will get
 * an error message from the compiler if you have an else if/else clause.
 *
 * These are macro wrappers for the normal glib memory allocation routines.
 * The numbers are stored in MEM_HOLDER defined below and changeable.  It
 * should be of type long, I wouldn't try it int if I were you.
 * Everytime memory is allocated, MEM_HOLDER goes up by the number of bytes,
 * and every deallocation makes MEM_HOLDER go down by the number of bytes
 * deallocated.  At the end of the program, MEM_HOLDER should be displayed
 * by some manner of print call to tell what the "results" are.  A negative
 * number probably means either glib screamed at you for freeing previously
 * freed memory, a segfault is imminent, (or has already happened) or I 
 * messed up which is probably the most likely.  :)
 *
 * The options data structure also contains fields for counting how many times
 * various memory allocation/deallocation calls were made.
 */
#define MEM_HEADER_H 

/* I'm just grabbing a stream that won't be used by name hopefully.
 * Ok fine, we'll force it.
 */
#ifdef _Q_
#  undef _Q_
#endif /* _Q_ */

#ifndef _Q_
#  define _Q_ stderr
#endif /* _Q_ */

#define MEM_HOLDER        options.MEM   /* This is where you store the long */

#ifndef DEBUGGING
#  ifdef GTKEYBOARD_MEMORY_DEBUGGING
#    undef GTKEYBOARD_MEMORY_DEBUGGING
#  endif /* GTKEYBOARD_MEMORY_DEBUGGING */
#endif /* DEBUGGING */

#ifdef GTKEYBOARD_MEMORY_DEBUGGING

/* Display what we know about the memory */
#  define MEM_REPORT        fprintf(_Q_,"|%ld|",MEM_HOLDER); fflush(_Q_);
#  define INC(x)            ++x;

/* Put the GLOBAL variable name here that holds your bytes allocated/freed 
 * Also, prefix with MY so it hopefully won't collide with anything else.
 */
#  define MEM_(x)              fprintf(_Q_,"%s",x); fflush(_Q_);
#  define _MY_G_FREE_(mem)     MEM_("FREE-"); MEM_HOLDER -= sizeof(mem); \
                               g_free(mem);
#  define _MY_G_NEW0_(t,c)     g_new0(t,c); MEM_("NEW0-");\
                               MEM_HOLDER+=(sizeof(t) * c);
#  define _MY_G_NEW_(t,c)      g_new(t,c); MEM_("NEW-");\
                               MEM_HOLDER+=(sizeof(t) * c);
#  define _MY_G_STRDUP_(x)     g_strdup(x); MEM_("STRDUP-");\
                               MEM_HOLDER+=(strlen(x) * sizeof(char));
#  define _MY_G_MALLOC_(x)     g_malloc(x); MEM_("MALLOC-");\
                               MEM_HOLDER+=x;

/* Cons me up some macros */
#  define g_new0_(t,c)         _MY_G_NEW0_(t,c);  INC(options.gnew0);
#  define g_free_(mem)         _MY_G_FREE_(mem);  INC(options.gfree);
#  define g_new_(t,c)          _MY_G_NEW_(t,c);   INC(options.gnew);
#  define g_strdup_(x)         _MY_G_STRDUP_(x);  INC(options.gstrdup);
#  define g_malloc_(x)         _MY_G_MALLOC_(x);  INC(options.gmalloc);
#  define MEM(x)               MEM_(x)                          

#else /* ! GTKEYBOARD_MEMORY_DEBUGGING */

#  define MEM_REPORT        ; /* Nothing */

/* The regular non-fun glib calls for distro copies of gtkeyboard. */
#  define g_new0_(t,c)      g_new0(t,c)
#  define g_free_(mem)      g_free(mem)
#  define g_new_(t,c)       g_new(t,c)
#  define g_strdup_(x)      g_strdup(x)
#  define g_malloc_(x)      g_malloc(x)
#  define MEM(x)            ;     /* Don't do anything */

#endif /* GTKEYBOARD_MEMORY_DEBUGGING */
/* EOF */

