#define _LARGEFILE64_SOURCE	/* required for GLIBC to enable stat64 and friends */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdarg.h>
#include <regex.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include "mt.h"
#include "error.h"
#include "globals.h"
#include "term.h"
#include "utils.h"
#include "mem.h"

#ifndef _DEBUG
#define MEMLOG(x)
void dump_mem(int sig)
{
}
#else
void MEMLOG(char *s, ...)
{
        va_list ap;
        FILE *fh = fopen("log.log", "a+");
        if (!fh)
                error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "error logging\n");

        va_start(ap, s);
        vfprintf(fh, s, ap);
        va_end(ap);

        fclose(fh);
}

typedef struct
{
	void *p;
	int size;

	char *file;
	char *function;
	int line;
} memlist;
memlist *pm = NULL;
int n_pm = 0;

void dump_mem(int sig)
{
	int loop;

	signal(SIGHUP, dump_mem);

	if (sig != SIGHUP)
		error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "Unexpected signal %d.\n", sig);

	MEMLOG("%d elements of memory used\n", n_pm);
	for(loop=0; loop<n_pm; loop++)
	{
		MEMLOG("%06d] %p %d (%s:%s@%d)\n", loop, pm[loop].p, pm[loop].size, pm[loop].file, pm[loop].function, pm[loop].line);
	}
	MEMLOG("--- finished memory dump\n");
}

int remove_mem_element(void *p)
{
	int old_size = 0;

	if (p)
	{
		int loop;

		for(loop=0; loop<n_pm; loop++)
		{
			if (pm[loop].p == p)
			{
				int n_to_move;

				old_size = pm[loop].size;

				n_to_move = (n_pm - loop) - 1;
				if (n_to_move > 0)
					memmove(&pm[loop], &pm[loop + 1], n_to_move * sizeof(memlist));
				else if (n_to_move < 0)
					error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "n_to_move < 0!\n");
				n_pm--;
				loop=-1;

				break;
			}
		}

		if (loop != -1)
		{
			MEMLOG("remove_mem_element: pointer %p not found\n", p);
		}

		if (n_pm)
		{
			pm = (memlist *)realloc(pm, sizeof(memlist) * n_pm);
			if (!pm) error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "Failed to shrink memory list to %d elements.\n", n_pm);
		}
		else
		{
			free(pm);
			pm = NULL;
		}
	}

	return old_size;
}
void add_mem_element(void *p, int size, char *file, const char *function, int line)
{
	pm = (memlist *)realloc(pm, sizeof(memlist) * (n_pm + 1));
	if (!pm) error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "Failed to grow memory list from %d elements.\n", n_pm);

	pm[n_pm].p = p;
	pm[n_pm].size = size;

	pm[n_pm].file     = file;
	pm[n_pm].function = (char *)function;
	pm[n_pm].line     = line;

	n_pm++;
}
#endif

void myfree(void *p)
{
#ifdef _DEBUG
	(void)remove_mem_element(p);
#endif
	free(p);
}

void * myrealloc(void *oldp, int new_size, char *file, const char *function, int line)
{
#ifdef _DEBUG
	int old_size;
	void *newp;

	if (new_size <= 0)
		error_exit(file, function, line, "Tried to allocate %d bytes which is wrong.\n", new_size);

	newp = realloc(oldp, new_size);
	if (!newp)
		error_exit(file, function, line, "Failed to reallocate a memory block to %d bytes.\n", new_size);
	old_size = remove_mem_element(oldp);
	add_mem_element(newp, new_size, file, function, line);
	signal(SIGHUP, dump_mem);

	if (new_size > old_size)
		memset(&((char *)newp)[old_size], 0xf1, new_size - old_size);

/*	rand_size = new_size - old_size;
	if (rand_size > 0)
	{
		MEMLOG("randomizing(%s) %d bytes\n", what, rand_size);
		memset(&((char *)newp)[old_size], rand_val, rand_size);
	}
*/
#else
	/* ----------------------------------------------------
	 * add code for repeatingly retry? -> then configurable
	 * via configurationfile with number of retries and/or
	 * sleep
	 * ----------------------------------------------------
	 */
	void *newp = realloc(oldp, new_size);
	if (!newp)
		error_exit(file, function, line, "Failed to reallocate a memory block to %d bytes.\n", new_size);
#endif

	return newp;
}

void * mymalloc(int size, char *file, const char *function, int line)
{
	return myrealloc(NULL, size, file, function, line);
}

char * mystrdup(char *in, char *file, const char *function, int line)
{
#ifdef _DEBUG
	int len = strlen(in) + 1;
	char *newp = (char *)mymalloc(len, file, function, line);

	memcpy(newp, in, len);

	return newp;
#else
	char *newp = strdup(in);
	if (!newp)
		error_exit(file, function, line, "Failed to duplicate a string: out of memory?\n");

	return newp;
#endif
}

#ifdef _DEBUG
void clean_memory(void)
{
	int loop;

	/* color schemes */
	for(loop=0; loop<n_cschemes; loop++)
	{
		int loop2;

		myfree(cschemes[loop].name);
		myfree(cschemes[loop].descr);

		for(loop2=0; loop2<cschemes[loop].n; loop2++)
		{
			regfree(&cschemes[loop].pentries[loop2].regex);
		}

		myfree(cschemes[loop].color_script.script);
		myfree(cschemes[loop].pentries);
	}
	myfree(cschemes);

	/* colors */
	myfree(cp.fg_color);
	myfree(cp.bg_color);

	/* text buffers */
	for(loop=0; loop<nfd; loop++)
		delete_be_in_buffer(&lb[loop]);
	myfree(lb);

	/* programs array */
	for(loop=0; loop<nfd; loop++)
	{
		proginfo *cur = &pi[loop];

		while(cur)
		{
			proginfo *pcur = cur;
			int loop2;

			for(loop2=0; loop2<cur -> n_strip; loop2++)
			{
				if ((cur -> pstrip)[loop2].type == STRIP_TYPE_REGEXP ||
				    (cur -> pstrip)[loop2].type == STRIP_KEEP_SUBSTR)
				{
					regfree(&(cur -> pstrip)[loop2].regex);
					myfree ((cur -> pstrip)[loop2].regex_str);
				}
				myfree ((cur -> pstrip)[loop2].del);
			}
			myfree(cur -> pstrip);

			myfree(cur -> filename);

			for(loop2=0; loop2<cur -> n_redirect; loop2++)
				myfree((cur -> predir)[loop2].redirect);
			myfree(cur -> predir);

			myfree(cur -> label);

			free_iat(&cur -> conversions);

			myfree(cur -> incomplete_line);
			myfree(cur -> win_title);

			delete_array(cur -> restart.diff.bcur, cur -> restart.diff.ncur);
			delete_array(cur -> restart.diff.bprev, cur -> restart.diff.nprev);

			myfree(cur -> repeat.last_line);

			free_iat(&cur -> cdef.color_schemes);

			delete_popup(cur -> status);
			delete_popup(cur -> data);

			for(loop2=0; loop2<cur -> n_re; loop2++)
				free_re(&(cur -> pre)[loop2]);
			myfree(cur -> pre);

			cur = cur -> next;

			if (pcur != &pi[loop])
				myfree(pcur);
		}
	}
	myfree(pi);

	/* parameters per file */
	for(loop=0; loop<n_pars_per_file; loop++)
	{
		int loop2;

		for(loop2=0; loop2<ppf[loop].n_colorschemes; loop2++)
			myfree(ppf[loop].colorschemes[loop2]);
		myfree(ppf[loop].colorschemes);

		if (ppf[loop].re_str)
		{
			regfree(&ppf[loop].regex);
			myfree(ppf[loop].re_str);
		}

		free_iat(&ppf[loop].filterschemes);
		free_iat(&ppf[loop].editschemes);

		for(loop2=0; loop2<ppf[loop].n_conversion_schemes; loop2++)
			myfree(ppf[loop].conversion_schemes[loop2]);
		myfree(ppf[loop].conversion_schemes);
	}
	myfree(ppf);

	/* conversions */
	for(loop=0; loop<n_conversions; loop++)
	{
		int loop2;

		myfree(conversions[loop].name);

		for(loop2=0; loop2<conversions[loop].n; loop2++)
			regfree(&conversions[loop].pcb[loop2].regex);
		myfree(conversions[loop].pcb);

		myfree(conversions[loop].pcs -> script);
		myfree(conversions[loop].pcs);
	}
	myfree(conversions);

	/* filterschemes */
	for(loop=0; loop<n_fs; loop++)
	{
		int loop2;

		myfree(pfs[loop].fs_name);
		myfree(pfs[loop].fs_desc);

		for(loop2=0; loop2<pfs[loop].n_re; loop2++)
			free_re(&pfs[loop].pre[loop2]);
		myfree(pfs[loop].pre);
	}
	myfree(pfs);

	/* edit schemes */
	for(loop=0; loop<n_es; loop++)
	{
		int loop2;

		myfree(pes[loop].es_name);
		myfree(pes[loop].es_desc);

		for(loop2=0; loop2<pes[loop].n_strips; loop2++)
		{
			regfree(&pes[loop].strips[loop2].regex);
			myfree(pes[loop].strips[loop2].regex_str);
			myfree(pes[loop].strips[loop2].del);
		}
		myfree(pes[loop].strips);
	}
	myfree(pes);

	/* keybindings */
	for(loop=0; loop<n_keybindings; loop++)
		myfree(keybindings[loop].command);
	myfree(keybindings);

	/* splitlines */
	for(loop=0; loop<n_splitlines; loop++)
		delete_popup(splitlines[loop]);
	myfree(splitlines);

	/* history */
	myfree(search_h.history_file);
	if (search_h.history)
	{
		for(loop=0; loop<search_h.history_size; loop++)
			myfree(search_h.history[loop]);
	}
	myfree(search_h.history);
	myfree(cmdfile_h.history_file);
	if (cmdfile_h.history)
	{
		for(loop=0; loop<cmdfile_h.history_size; loop++)
			myfree(cmdfile_h.history[loop]);
	}
	myfree(cmdfile_h.history);

	myfree(color_names);
	myfree(window_number);
	myfree(subwindow_number);
	myfree(defaultcscheme);
	myfree(shell);
	myfree(ts_format);
	myfree(cnv_ts_format);
	myfree(statusline_ts_format);
	myfree(tail);
	myfree(set_title);
	myfree(replace_by_markerline);
	myfree(line_ts_format);
	myfree(n_win_per_col);
	myfree(syslog_ts_format);

	myfree(global_find);

	MEMLOG("finished clean_memory\n");
}
#endif


syntax highlighted by Code2HTML, v. 0.9.1