/*
    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:	field.c							*
 *									*
 * Description:	This file contains the public and private function	*
 *		definitions relating to record fields and the		*
 *		corresponding virtual machine instruction.		*
 ************************************************************************/

# include "debug.h"
# include "error.h"
# include "field.h"
# include "execute.h"

# define MaxFields 160


typedef struct field {
    short type;
    short handler;
    short offset;
} *Field;

static struct field field_table [D_NumTypes] [MaxFields];


/************************************************************************
 * Function:	add_field						*
 *									*
 * Description:	Adds a field to the field table.  The table is a two-	*
 *		dimensional array indexed by type and field number.	*
 ************************************************************************/

void add_field (rtype, name, ftype, offset, handler)
    int		rtype;
    char       *name;
    int		ftype;
    unsigned	offset;
    TrapHandler	handler;
{
    ste  *s;
    Field f;


    s = st_insert (&field_st, name, FieldOp);

    if (s -> idx >= MaxFields) {
	rterror ("too may field entries");
	exit (1);
    }


    f = &field_table [rtype] [s -> idx];
    f -> type	 = ftype;
    f -> offset	 = offset;
    f -> handler = AddTrap (handler);
}


/************************************************************************
 * Function:	field_op						*
 *									*
 * Description:	Pops the descriptor on the top of the stack, looks up	*
 *		the field whose given at the next address, and places	*
 *		the result on the stack.  If the field type is an array	*
 *		then the appropriate array constructor is called.  If	*
 *		the field is a pair then the offset is added to the	*
 *		current pointer.  Otherwise, the current pointer is	*
 *		first dereferenced and then the offset is added.	*
 ************************************************************************/

int field_op ( )
{
    void       *ptr;
    descriptor *record;
    descriptor *result;
    descriptor	temp;
    int		type_error;
    int		index;
    Field	f;


    result = top ( );
    temp = *result;
    record = &temp;

    index = fetch (pc ++).ival;
    record = deref (record);


    if ((f = &field_table [D_Type (record)] [index]) -> type != T_Null) {
	type_error = F_False;
	ptr = D_Pointer (record);

	if (ptr && (D_Direct (record) || *(char **) ptr)) {

	    switch (D_Type (record)) {
	    case T_Analysis:
	    case T_Pair:
	    case T_Problem:
		ptr = (void *) ((char *) D_Pointer (record) + f -> offset);
		break;

	    default:
		ptr = (void *) (*(char **) D_Pointer (record) + f -> offset);
		break;
	    }

	    if (f -> type != T_Array) {
		D_Type    (result) = f -> type;
		D_Temp    (result) = F_False;
		D_Trapped (result) = f -> handler;
		D_Pointer (result) = ptr;
	    } else {
		CreateData (result, NULL, NULL, T_Array, ptr, 0, T_Null, 0);
		CallTrap (f -> handler, record, &result);
	    }

	} else {
	    D_Type    (result) = T_Null;
	    D_Temp    (result) = F_False;
	    D_Trapped (result) = F_False;
	    D_Pointer (result) = NULL;
	}

    } else {
	type_error = F_True;
	TypeError ("has no such field", record, NULL, NULL, F_False);
    }


    RecycleData (record);
    d_printf ("field ans =\n");
    d_PrintData (result);

    return type_error == F_True;
}


syntax highlighted by Code2HTML, v. 0.9.1