/*
 *  Project   : tin - a threaded Netnews reader
 *  Module    : memory.c
 *  Author    : I.Lea & R.Skrenta
 *  Created   : 01-04-91
 *  Updated   : 03-06-92
 *  Notes     :
 *  Copyright : (c) Copyright 1991-92 by Iain Lea & Rich Skrenta
 *              You may  freely  copy or  redistribute  this software,
 *              so  long as there is no profit made from its use, sale
 *              trade or  reproduction.  You may not change this copy-
 *              right notice, and it must be included in any copy made
 */

#include	"tin.h"

int *my_group;					/* .newsrc --> active[] */
int *unread;					/* highest art read in group */
long *base;
struct group_t *active;			/* active file */
struct article_t *arts;

/*
 *  Dynamic table management
 *  These settings are memory conservative:  small initial allocations
 *  and a 50% expansion on table overflow.  A fast vm system with
 *  much memory might want to start with higher initial allocations
 *  and a 100% expansion on overflow, especially for the arts[] array.
 */

void init_alloc ()
{
	max_active = DEFAULT_ACTIVE_NUM;
	max_art = DEFAULT_ARTICLE_NUM;

	active = (struct group_t *) my_malloc ((unsigned) sizeof(*active) * max_active);
	my_group = (int *) my_malloc ((unsigned) sizeof(int) * max_active);
	unread = (int *) my_malloc ((unsigned) sizeof(int) * max_active);

	arts = (struct article_t *) my_malloc ((unsigned) sizeof(*arts) * max_art);
	base = (long *) my_malloc ((unsigned) sizeof(long) * max_art);

	max_kill = DEFAULT_KILL_NUM;
	
	killf = (struct kill_t *) my_malloc ((unsigned) sizeof(*killf) * max_kill);

	max_save = DEFAULT_SAVE_NUM;
	
	save = (struct save_t *) my_malloc ((unsigned) sizeof(*save) * max_save);

	screen = (struct screen_t *) 0;
}


void expand_art()
{
	max_art += max_art / 2;		/* increase by 50% */

	arts = (struct article_t *) my_realloc ((char *) arts, (unsigned) sizeof(*arts) * max_art);
	base = (long *) my_realloc ((char *) base, (unsigned) sizeof(long) * max_art);
}


void expand_active()
{
	max_active += max_active / 2;		/* increase by 50% */

	if (active == (struct group_t *) 0) {
		active = (struct group_t *) my_malloc ((unsigned) sizeof(*active) * max_active);
		my_group = (int *) my_malloc ((unsigned) sizeof(int) * max_active);
		unread = (int *) my_malloc ((unsigned) sizeof(int) * max_active);
	} else {
		active = (struct group_t *) my_realloc((char *) active,
				 (unsigned) sizeof(*active) * max_active);
		my_group = (int *) my_realloc((char *) my_group, (unsigned) sizeof(int) * max_active);
		unread = (int *) my_realloc((char *) unread, (unsigned) sizeof(int) * max_active);
	}
}


void expand_kill()
{
	max_kill += max_kill / 2;		/* increase by 50% */

	killf = (struct kill_t *) my_realloc((char *) killf, (unsigned) sizeof(struct kill_t) * max_kill);
}


void expand_save()
{
	max_save += max_save / 2;		/* increase by 50% */

	save = (struct save_t *) my_realloc((char *) save, (unsigned) sizeof(struct save_t) * max_save);
}


void init_screen_array (allocate)
	int allocate;
{
	int i;

	if (allocate) {
		screen = (struct screen_t *) my_malloc(
			(unsigned) sizeof(struct screen_t) * LINES+1);

		for (i=0 ; i < LINES ; i++) {
			screen[i].col = (char *) my_malloc ((unsigned) COLS+2);
		}
	} else {
		if (screen != (struct screen_t *) 0) {
			for (i=0 ; i < LINES ; i++) {
				if (screen[i].col != (char *) 0) {
					free ((char *) screen[i].col);
					screen[i].col = (char *) 0;
				}
			}	

			free ((char *) screen);
			screen = (struct screen_t *) 0;
		}
	}
}


void free_all_arrays ()
{
	hash_reclaim ();
	
	init_screen_array (FALSE);

	free_art_array ();

	if (arts != (struct article_t *) 0) {
		free ((char *) arts);
		arts = (struct article_t *) 0;
	}

	free_active_arrays ();

	if (base != (long *) 0) {
		free ((char *) base);
		base = (long *) 0;
	}

	if (killf != (struct kill_t *) 0) {
		free_kill_array ();
		if (killf != (struct kill_t *) 0) {
			free ((char *) killf);
			killf = (struct kill_t *) 0;
		}
	}

	if (save != (struct save_t *) 0) {
		free_save_array ();
		if (save != (struct save_t *) 0) {
			free ((char *) save);
			save = (struct save_t *) 0;
		}
	}
}


void free_art_array ()
{
	register int i;

	for (i=0 ; i < top ; i++) {
		arts[i].artnum = 0L;
		arts[i].thread = ART_EXPIRED;
		arts[i].inthread = FALSE;
		arts[i].unread = ART_UNREAD;
		arts[i].killed = FALSE;
		arts[i].tagged = FALSE;
		arts[i].hot = FALSE;
		arts[i].date[0] = '\0';
		if (arts[i].part != (char *) 0) {
			free ((char *) arts[i].part);
			arts[i].part = (char *) 0;
		}
		if (arts[i].patch != (char *) 0) {
			free ((char *) arts[i].patch);
			arts[i].patch = (char *) 0;
		}
		if (arts[i].xref != NULL) {
			free ((char *) arts[i].xref);
			arts[i].xref = NULL;
		}
	}
}


void free_active_arrays ()
{
	register int i;
	
	if (my_group != (int *) 0) {			/* my_group[] */
		free ((char *) my_group);
		my_group = (int *) 0;
	}

	if (unread != (int *) 0) {				/* unread[] */
		free ((char *) unread);
		unread = (int *) 0;
	}

	if (active != (struct group_t *) 0) {	/* active[] */
		for (i=0 ; i < num_active ; i++) {
			if (active[i].name != (char *) 0) {
				free ((char *) active[i].name);
				active[i].name = (char *) 0;
			}
			if (active[i].description != (char *) 0) {
				free ((char *) active[i].description);
				active[i].description = (char *) 0;
			}
			if (active[i].attribute.server != (char *) 0) {
				free ((char *) active[i].attribute.server);
				active[i].attribute.server = (char *) 0;
			}
			if (active[i].attribute.maildir != (char *) 0 &&
			    active[i].attribute.maildir != default_maildir) {
				free ((char *) active[i].attribute.maildir);
				active[i].attribute.maildir = (char *) 0;
			}
			if (active[i].attribute.savedir != (char *) 0 &&
			    active[i].attribute.savedir != default_savedir) {
				free ((char *) active[i].attribute.savedir);
				active[i].attribute.savedir = (char *) 0;
			}
			if (active[i].attribute.sigfile != (char *) 0 &&
			    active[i].attribute.sigfile != default_sigfile) {
				free ((char *) active[i].attribute.sigfile);
				active[i].attribute.sigfile = (char *) 0;
			}
		}
		if (active != (struct group_t *) 0) {
			free ((char *) active);
			active = (struct group_t *) 0;
		}
	}
}


void free_kill_array ()
{
	int i;
	
	for (i=0 ; i < kill_num ; i++) {
		if (killf[i].kill_subj != (char *) 0) {
			free ((char *) killf[i].kill_subj);
			killf[i].kill_subj = (char *) 0;
		}
		if (killf[i].kill_from != (char *) 0) {
			free ((char *) killf[i].kill_from);
			killf[i].kill_from = (char *) 0;
		}
	}
}


/*
 *  reset save list array to 0 and free's all its allocated memory
 */
 
void free_save_array ()
{
	int i;
	
	for (i=0 ; i < save_num ; i++) {
		if (save[i].subject != (char *) 0) {
			free ((char *) save[i].subject);
			save[i].subject = (char *) 0;
		}
		if (save[i].archive != (char *) 0) {
			free ((char *) save[i].archive);
			save[i].archive = (char *) 0;
		}
		if (save[i].dir != (char *) 0) {
			free ((char *) save[i].dir);
			save[i].dir = (char *) 0;
		}
		if (save[i].file != (char *) 0) {
			free ((char *) save[i].file);
			save[i].file = (char *) 0;
		}
		if (save[i].part != (char *) 0) {
			free ((char *) save[i].part);
			save[i].part = (char *) 0;
		}
		if (save[i].patch != (char *) 0) {
			free ((char *) save[i].patch);
			save[i].patch = (char *) 0;
		}
		save[i].index   = -1;
		save[i].saved   = FALSE;
		save[i].is_mailbox = FALSE;
	}
	
	save_num = 0;
}


char *my_malloc (size)
	unsigned size;
{
	char *p;

	if ((p = (char *) calloc (1, (int) size)) == NULL) {
		error_message (txt_out_of_memory, progname);
		tin_done (1);
	}
	return p;
}


char *my_realloc (p, size)
	char *p;
	unsigned size;
{
	if (! p) {
		p = (char *) calloc (1, (int) size);
	} else {
		p = (char *) realloc (p, (int) size);
	}

	if (! p) {
		error_message (txt_out_of_memory, progname);
		tin_done (1);
	}
	return p;
}
