/*  Functions for working with tree nodes - Jan 1989
    Copyright (C) 1990  Marty White

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include <stdio.h>
#include "compiler.h"

#ifdef __STDHEADERS__
/*#include <dos.h>*/
#include <stdlib.h>
#include <string.h>
#endif

#include "physcalc.h"
#include "physdecl.h"

#ifdef __PROTOTYPES__
NODEP allocnode(int t, int bytes);
LOCAL void dealloclist(NODEP n);
#else
LOCAL void dealloclist();
#endif

#define STACKSIZE (1024 * 8)	/* 8K stack space */

EXPORT int nodecount;

EXPORT void initnodes()	/* WARNING!! May not be compatible! */
{
#ifdef __DESMETC__
	freeall(STACKSIZE);		/* Leave stack space */
#endif
}
#ifdef __TURBOC__
extern unsigned _stklen = STACKSIZE;		/* set stack */
#endif


EXPORT void out_of_memory(s)
char const *s;
{
	printf("\nOut of memory. [%s]\n%d nodes were allocated.\n",s,nodecount);
	exit(1);
}

EXPORT NODEP allocnode(t,bytes)	/* allocate a node & data space & set type */
int t,bytes;
{
	NODEP n;

	n = (NODEP) malloc(sizeof(NODE));	/* Allocate space for node itself */
	if (n==NULL)
		out_of_memory("allocnode");
	n->type = t;
	n->data=malloc(bytes);	/* Allocate space for data */
	if (n->data==NULL)
		out_of_memory("allocnode");
	nodecount++;
	return n;
}

EXPORT char *reallocnode(n,t,bytes)	/* Reset data size & type */
NODEP n;
int t,bytes;
{
	register VOID *p;

	if (n->type >= LNODE)
		dealloclist(n);
	p = realloc(n->data,bytes);
	if (p==NULL)
		out_of_memory("reallocnode");
	n->type = t;
	n->data = p;
	return p;
}

EXPORT NODEP allocsnode(s)	/* allocate & initialize a string-node */
char const *s;
{
	NODEP n;

	n = allocnode(SNODE,strlen(s)+1);
	strcpy(n->data->str,s);
	return n;
}

EXPORT NODEP allocdnode(x)	/* allocate & init a double-type node */
double x;
{
	NODEP n;

	n = allocnode(DNODE,sizeof(double));
	n->data->dbl = x;
	return n;
}

EXPORT NODEP allocinode(i)	/* alloc a long-int node */
long i;
{
	NODEP n;

	n = allocnode(INODE,sizeof(long));
	n->data->lng = i;
	return n;
}

EXPORT NODEP allocfnode(num,den)	/* alloc a fracton node */
int num,den;
{
	NODEP n;

	n = allocnode(FNODE,sizeof(struct fractstruct));
	n->data->frt.numer = num;
	n->data->frt.denom = den;
	return n;
}

EXPORT NODEP allocnnode()
{
	NODEP n;

	n = allocnode(NNODE,sizeof(struct d_num));
	erasednum((DNUM *)(n->data));
	return n;
}

EXPORT NODEP alloclnode(t)	/* allocate an empty list-type node of type t */
int t;
{
	NODEP n;

	n = allocnode(t,sizeof(n));
	n->data->list[0] = NULL;
	return n;
}

EXPORT NODEP alloclnode1(t,n1)
int t;
NODEP n1;
{
	NODEP n2;

	n2 = alloclnode(t);
	linknode(n2,n1);
	return n2;
}

EXPORT NODEP alloclnode2(t,n1,n2) /* allocate a list node with 2 sub nodes */
int t;
NODEP n1,n2;
{
	NODEP n3;

	n3 = alloclnode(t);
	linknode(n3,n1);
	linknode(n3,n2);
	return n3;
}

EXPORT NODEP linknode(n1,n2)	/* Point n1 to n2, return n2 */
NODEP n1,n2;			/* On failure, return NULL and do not link */
{
	int i=0;
	VOID *p;

	if (n1->type < LNODE)
		return NULL;
	while (n1->data->list[i])	/* set i to end of list */
		i++;
	p = realloc(n1->data,sizeof(n1->data->list[0])*(i+2));
	if (p==NULL)
		out_of_memory("linknode");
	n1->data = p;
	n1->data->list[i] = n2;
	n1->data->list[++i] = NULL;
	return n2;
}

EXPORT NODEP unlinknode(n1,n2)
	/* zap n1's pointer to n2 (if it has one);return n2 */
NODEP n1,n2;	/* On failure, return NULL */
{
	int i=0;

	if (n1->type < LNODE)
		return NULL;
	while ( n1->data->list[i] && n1->data->list[i]!=n2 )
		i++;
	if (n1->data->list[i]) {
		while (n1->data->list[i]=n1->data->list[i+1])
			i++;
		i++;
		n1->data = realloc( n1->data, sizeof(n1->data->list[0])*i );
		if (n1->data==NULL)
			out_of_memory("unlinknode");
	}
	return n2;
}

LOCAL void dealloclist(n)		/* de-allocate all the sub-nodes of n */
NODEP n;
{
	int i=0;

	if (n->type >= LNODE && n->data) {
		while (n->data->list[i])
			deallocnode(n->data->list[i++]);
		n->data->list[0] = NULL;
	}
}

EXPORT void deallocnode(n)	/* de-allocate a node & its sub-nodes if any */
NODEP n;
{
	if (n) {
		if (n->type >= LNODE)
			dealloclist(n);
		free(n->data);
		free(n);
		nodecount--;
	}
}

EXPORT int cmpnode(n1,n2)	/* compare for equal contents */
NODEP n1,n2;
{
	NODEP n3,n4;
	int i;

	if (n1==n2)			/* simple case of the same node */
		return TRUE;
	if (!n1 || !n2 || n1->type != n2->type)
		return FALSE;
	switch (n1->type) {
        case 0 /*NULL*/:
			return TRUE;
		case SNODE:
			return !strcmp(n1->data->str,n2->data->str);
		case DNODE:
			return n1->data->dbl == n2->data->dbl;
		case INODE:
			return n1->data->lng == n2->data->lng;
		case FNODE:		/* TD: Compare fractional and dimensional nodes */
		case NNODE:
			return FALSE;
		default:
			i=0;
			while (n3 = n1->data->list[i]) {
				n4 = n2->data->list[i];
				if (!n4 || !cmpnode(n3,n4))
					return FALSE;
				i++;
			}
			return !n2->data->list[i];
	}
	return 0;	/* code is never reached */
}

EXPORT int nodesize(n)	/* return size in bytes of associated data */
NODEP n;
{
	register int b,i;

	switch (n->type) {
    case 0 /*NULL*/:
		b = 0;
		break;
	case INODE:
		b = sizeof(long);
		break;
	case FNODE:
		b = sizeof(struct fractstruct);
		break;
	case DNODE:
		b = sizeof(double);
		break;
	case NNODE:
		b = sizeof(DNUM);
		break;
	case SNODE:
		b = strlen(n->data->str) + 1;
		break;
	default:
		i = 0;
		while (n->data->list[i++])
			;
		b = i * sizeof(NODEP);
	}
	return b;
}

EXPORT void bytecopy(dst, src, bytes)
char *dst;
char const *src;
int bytes;
{
	while (bytes--)
		*dst++ = *src++;
}

EXPORT NODEP copynode(n)	/* Create a duplicate of node n (including sub-nodes) */
NODEP n;			/* Will hang on self-referential node structures */
{
	NODEP n2,n3;
	int i=0;

	switch (n->type	) {
    case 0 /*NULL*/:
		n2 = NULL;
		break;
	case SNODE:
	case INODE:
	case FNODE:
	case DNODE:
	case NNODE:
		n2 = allocnode(n->type,i=nodesize(n));
		bytecopy(n2->data,n->data,i);
		break;
	default:	/* List node */
		n2 = alloclnode(n->type);
		while (n->data->list[i]) {
			n3 = copynode(n->data->list[i]);
			linknode(n2,n3);
			i++;
		}
	}
	return n2;
}


syntax highlighted by Code2HTML, v. 0.9.1