/*
    This file is part of the FElt finite element analysis package.
    Copyright (C) 1993-2000 Jason I. Gobat and Darren C. Atkinson

    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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/************************************************************************
 * File:	descriptor.c						*
 *									*
 * Description:	This file contains the public and private function	*
 *		definitions for descriptors.				*
 ************************************************************************/

# include "trap.h"
# include "debug.h"
# include "desctab.h"
# include "allocate.h"
# include "descriptor.h"
# include VAR_ARGS_INCLUDE

static descriptor *reused;


/************************************************************************
 * Function:	CreateData						*
 *									*
 * Description:	Creates new data for a descriptor using the data of	*
 *		other descriptors if they are temporary.		*
 ************************************************************************/

# ifdef UseFunctionPrototypes
void CreateData (descriptor *d, descriptor *a, descriptor *b, int type, ...)
# else
void CreateData (d, a, b, type, va_alist)
    descriptor *d;
    descriptor *a;
    descriptor *b;
    int		type;
    va_dcl
# endif
{
    void    *ptr;
    int      length;
    int      handler;
    unsigned ncols;
    unsigned nrows;
    va_list  ap;


    if (a && D_Type (a) == type && D_Writable (a)) {
	D_Type    (d) = type;
	D_Union   (d) = D_Union (a);
	D_Trapped (d) = F_False;
	D_Temp    (d) = F_True;
	reused = a;
	d_printf ("new %s (%p) from first\n", D_TypeName (d), D_Pointer (d));

    } else if (b && D_Type (b) == type && D_Writable (b)) {
	D_Type    (d) = type;
	D_Union   (d) = D_Union (b);
	D_Trapped (d) = F_False;
	D_Temp    (d) = F_True;
	reused = b;
	d_printf ("new %s (%p) from second\n", D_TypeName (d), D_Pointer (d));

    } else {
	D_Type    (d) = type;
	D_Trapped (d) = F_False;
	D_Temp    (d) = F_True;
	reused = NULL;
	VA_START (ap, type);

	switch (type) {
	case T_Null:
	    D_Pointer (d) = NULL;
	    break;


	case T_Variable:
	    D_Pointer (d) = NULL;
	    break;


	case T_Function:
	    D_Function (d) = CreateFunction (va_arg (ap, char *));
	    break;


	case T_Intrinsic:
	    D_Intrinsic (d) = va_arg (ap, int);
	    break;


	case T_String:
	    D_String (d) = New (char *);
	    *D_String (d) = Allocate (char, va_arg (ap, int));
	    break;


	case T_Double:
	    D_Double (d) = New (double);
	    break;


	case T_Int:
	    D_Int (d) = New (int);
	    break;


	case T_Byte:
	    D_Byte (d) = New (char);
	    break;


	case T_Array:
	    ptr     = va_arg (ap, void *);
	    type    = va_arg (ap, int);
	    length  = va_arg (ap, int);
	    handler = va_arg (ap, int);
	    D_Array (d) = CreateArray (ptr, type, length, handler);
	    break;


	case T_Row:
	    D_Pointer (d) = NULL;
	    break;


	case T_Matrix:
	    nrows = va_arg (ap, unsigned);
	    ncols = va_arg (ap, unsigned);
	    D_Matrix (d) = CreateFullMatrix (nrows, ncols);
	    break;


	default:
	    break;
	}

	d_printf ("new %s (%p)\n", D_TypeName (d), D_Pointer (d));
	va_end (ap);
    } 
}


/************************************************************************
 * Function:	AssignData						*
 *									*
 * Description:	Assigns the data of a descriptor to another.  The	*
 *		address of the source descriptor is passed so that it	*
 *		may returned to the caller if modified.  A trapped	*
 *		variable handler may attempt to coerce the source data	*
 *		to perform the assignment.				*
 ************************************************************************/

int AssignData (dest, srcp)
    descriptor  *dest;
    descriptor **srcp;
{
    char       *s;
    Matrix	a;
    Matrix	b;
    descriptor *src;
    descriptor *reuse;


    if (dest == *srcp)
	return 0;


    if (D_Trapped (dest) != F_False)
	return CallTrap (D_Trapped (dest), dest, srcp);

    src = *srcp;

    if (D_Temp (src) == F_True) {
	d_printf ("assignment from temporary\n");
	FreeData  (dest);
	D_Type    (dest) = D_Type (src);
	D_Temp	  (dest) = F_True;
	D_Trapped (dest) = F_False;
	D_Union   (dest) = D_Union (src);
	reused = src;

    } else {
	reused = NULL;
	D_Temp (dest) = F_True;
	d_printf ("assignment from non-temporary\n");


	switch (D_Type (src)) {
	case T_Null:
	    FreeData  (dest);
	    D_Type    (dest) = T_Null;
	    D_Temp    (dest) = F_False;
	    D_Trapped (dest) = F_False;
	    D_Pointer (dest) = NULL;
	    break;


	case T_Variable:
	    AssignData (dest, &D_Variable (src));
	    break;


	case T_Function:
	    FreeData  (dest);
	    D_Type     (dest) = T_Function;
	    D_Temp     (dest) = F_True;
	    D_Trapped  (dest) = F_False;
	    D_Function (dest) = CopyFunction (D_Function (src));
	    break;


	case T_Intrinsic:
	    FreeData	(dest);
	    D_Type	(dest) = T_Intrinsic;
	    D_Temp	(dest) = F_False;
	    D_Trapped	(dest) = F_False;
	    D_Intrinsic	(dest) = D_Intrinsic (src);
	    break;


	case T_String:
	    s = *D_String (src);
	    FreeData (dest);
	    CreateData (dest, NULL, NULL, T_String, strlen (s) + 1);
	    strcpy (*D_String (dest), s);
	    break;


	case T_Double:
	    if (!(reuse = D_Type (dest) == T_Double ? dest : NULL))
		FreeData (dest);

	    CreateData (dest, reuse, NULL, T_Double);
	    *D_Double (dest) = *D_Double (src);
	    break;


	case T_Int:
	    if (!(reuse = D_Type (dest) == T_Int ? dest : NULL))
		FreeData (dest);

	    CreateData (dest, reuse, NULL, T_Int);
	    *D_Int (dest) = *D_Int (src);
	    break;


	case T_Byte:
	    if (!(reuse = D_Type (dest) == T_Byte ? dest : NULL))
		FreeData (dest);

	    CreateData (dest, reuse, NULL, T_Byte);
	    *D_Byte (dest) = *D_Byte (src);
	    break;


	case T_Array:
	    FreeData  (dest);
	    D_Type    (dest) = T_Array;
	    D_Temp    (dest) = F_False;
	    D_Trapped (dest) = D_Trapped (src);
	    D_Array   (dest) = CopyArray (D_Array (src));
	    break;


	case T_Matrix:
	    a = D_Matrix (src);
	    reuse = NULL;
	    if (D_Type (dest) == T_Matrix) {
		b = D_Matrix (dest);
		if (Mrows (a) == Mrows (b) && Mcols (a) == Mcols (b))
		    reuse = dest;
	    }

	    if (!reuse)
		FreeData (dest);

	    if (IsCompact (a)) {
		FreeData (dest);
		D_Type	  (dest) = T_Matrix;
		D_Temp	  (dest) = F_False;
		D_Trapped (dest) = F_False;
		D_Matrix  (dest) = CreateCopyMatrix (a);
	    } else {
		CreateData (dest, reuse, NULL, T_Matrix, Mrows (a), Mcols (a));
		CopyMatrix (D_Matrix (dest), a);
	    }
	    break;


	case T_External:
	    D_Type     (dest) = T_External;
	    D_Temp     (dest) = F_False;
	    D_Trapped  (dest) = F_False;
	    dest->u.ptr       = D_External (src);
	    break;


	default:
	    D_Type    (dest) = D_Type (src);
	    D_Temp    (dest) = F_False;
	    D_Trapped (dest) = F_False;
	    D_Pointer (dest) = D_Pointer (src);
	    break;
	}
    }

    return 0;
}


/************************************************************************
 * Function:	AssignObject						*
 *									*
 * Description:	Special interface to AssignData() that creates a fake	*
 *		descriptor and also sets the destination descriptor to	*
 *		be non-temporary.  This is used in assigning to shared	*
 *		arguments.						*
 ************************************************************************/

int AssignObject (dest, type, temp, ptr)
    descriptor *dest;
    int		type;
    int		temp;
    void       *ptr;
{
    descriptor *src;
    descriptor	scratch;
    int		status;


    src = &scratch;

    D_Type    (src) = type;
    D_Temp    (src) = temp;
    D_Trapped (src) = F_False;
    D_Pointer (src) = ptr;

    if (!(status = AssignData (dest, &src)))
	D_Temp (dest) = F_False;

    return status;
}


/************************************************************************
 * Function:	RecycleData						*
 *									*
 * Description:	Deallocates the data of a descriptor if it is		*
 *		temporary and has not been reused by CreateData().	*
 ************************************************************************/

void RecycleData (d)
    descriptor *d;
{
    if (d && D_Temp (d) == F_True && d != reused)
	FreeData (d);
    else if (d && D_Trapped (d) != F_False && d != reused)
	CallTrap (D_Trapped (d), d, NULL);
    else if (d == reused)
	reused = NULL;
}


/************************************************************************
 * Function:	FreeData						*
 *									*
 * Description:	Deallocates the data of a descriptor.			*
 ************************************************************************/

void FreeData (d)
    descriptor *d;
{
    if (d) {
	d_printf ("freeing %s (%p)\n", D_TypeName (d), D_Pointer (d));


	if (D_Trapped (d) != F_False)
	    CallTrap (D_Trapped (d), d, NULL);

	switch (D_Type (d)) {
	case T_Null:
	    break;


	case T_Variable:
	    break;


	case T_Function:
	    DestroyFunction (D_Function (d));
	    break;


	case T_Intrinsic:
	    break;


	case T_String:
	    Deallocate (*D_String (d));
	    Delete (D_String (d));
	    break;


	case T_Double:
	    Delete (D_Double (d));
	    break;


	case T_Int:
	    Delete (D_Int (d));
	    break;


	case T_Byte:
	    Delete (D_Byte (d));
	    break;


	case T_Array:
	    DestroyArray (D_Array (d));
	    break;


	case T_Row:
	    break;


	case T_Matrix:
	    DestroyMatrix (D_Matrix (d));
	    break;


	default:
	    break;
	}
    }
}


/************************************************************************
 * Function:	PrintData						*
 *									*
 * Description:	Prints the data of a descriptor.			*
 ************************************************************************/

void PrintData (d)
    descriptor *d;
{
    if (d) {
	switch (D_Type (d)) {
	case T_Null:
	    fprintf (stderr, "\tnull\n");
	    break;


	case T_Variable:
	    PrintData (D_Variable (d));
	    break;


	case T_Function:
	    fprintf (stderr, "\tfunction %s\n", D_Function (d) -> name);
	    break;


	case T_Intrinsic:
	    fprintf (stderr, "\tintrinsic %d\n", D_Intrinsic (d));
	    break;


	case T_String:
	    fprintf (stderr, "\t%s\n", *D_String (d));
	    break;


	case T_Double:
	    fprintf (stderr, "\t%g\n", *D_Double (d));
	    break;


	case T_Int:
	    fprintf (stderr, "\t%d\n", *D_Int (d));
	    break;


	case T_Byte:
	    fprintf (stderr, "\t%d\n", *D_Byte (d));
	    break;


	case T_Array:
	    fprintf (stderr, "\tarray\n");
	    break;


	case T_Row:
	    fprintf (stderr, "\trow\n");
	    break;


	case T_Matrix:
	    PrintMatrix (D_Matrix (d), stderr);
	    break;


	case T_MatrixPtr:
	    fprintf (stderr, "\tmatrix_ptr\n");
	    break;


	case T_Constraint:
	    fprintf (stderr, "\tconstraint\n");
	    break;


	case T_Definition:
	    fprintf (stderr, "\tdefinition\n");
	    break;


	case T_Element:
	    fprintf (stderr, "\telement\n");
	    break;


	case T_Force:
	    fprintf (stderr, "\tforce\n");
	    break;


	case T_Load:
	    fprintf (stderr, "\tload\n");
	    break;


	case T_Material:
	    fprintf (stderr, "\tmaterial\n");
	    break;


	case T_Node:
	    fprintf (stderr, "\tnode\n");
	    break;


	case T_Pair:
	    fprintf (stderr, "\tpair\n");
	    break;


	case T_External:
	   fprintf (stderr, "\texternal\n");
	   break;


	default:
	    fprintf (stderr, "\twhat are you trying to print?\n");
	    break;
	}
    }
}


syntax highlighted by Code2HTML, v. 0.9.1