/*
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: coerce.c *
* *
* Description: This file contains the function definitions for *
* coercing data from one type to another. *
************************************************************************/
# include <ctype.h>
# include "trap.h"
# include "coerce.h"
# include "execute.h"
# include "allocate.h"
# include "our-stdlib.h"
# define NumStatic 16
static int count;
static char strings [NumStatic] [256];
static union {
char *sval;
double dval;
int ival;
char bval;
} data [NumStatic];
static descriptor array [NumStatic];
/************************************************************************
* Function: strict *
* *
* Description: Trapped variable handler for strictly typed array *
* members. *
************************************************************************/
static int strict (dest, src)
descriptor *dest;
descriptor **src;
{
/* This data is never recycled. */
if (!src)
return 0;
*src = CoerceData (*src, D_Type (dest));
if (D_Type (dest) != D_Type (*src)) {
TypeError ("=", dest, *src, NULL, F_False);
return 1;
}
switch (D_Type (dest)) {
case T_Byte:
*D_Byte (dest) = *D_Byte (*src);
break;
case T_Int:
*D_Int (dest) = *D_Int (*src);
break;
case T_Double:
*D_Double (dest) = *D_Double (*src);
break;
default:
TypeError ("=", dest, *src, NULL, F_False);
return 1;
}
return 0;
}
/************************************************************************
* Function: CoerceData *
* *
* Description: Coerces the data of a descriptor from one type to *
* another. The following types may be coerced: *
* *
* double -> string, integer, byte *
* integer -> string, double, byte *
* byte -> string, double, integer *
* string -> double, integer, byte + *
* matrix -> string, double, integer, byte + *
* array -> string, double, integer, byte + *
* *
* A string may be coerced to a numeric type only if the *
* entire string evaluates to a number. A matrix may be *
* coerced to a scalar type only if it consists of a *
* single element. An array may be coerced to a scalar if *
* it consists of a single element. An array is *
* automatically coerced to a matrix by this function if *
* the element type of the array is numeric. *
************************************************************************/
descriptor *CoerceData (d, type)
descriptor *d;
int type;
{
Matrix a;
Array arr;
char *ptr;
descriptor *coerced;
unsigned i;
count = (count + 1) % NumStatic;
if (D_Type (d) == T_MatrixPtr) {
a = *D_MatrixPtr (d);
d = &array [count];
D_Type (d) = T_Matrix;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_Matrix (d) = a;
}
/* Since arrays are only used within the felt code itself, they should
appear as matrices to the outside world. */
if (D_Type (d) == T_Array && D_Array (d) -> length) {
arr = D_Array (d);
coerced = &array [count];
count = (count + 1) % NumStatic;
switch (arr -> type) {
case T_Int:
CreateData (coerced, NULL, NULL, T_Matrix, 1, arr -> length);
a = D_Matrix (coerced);
ptr = (char *) arr -> ptr + arr -> elt_size;
for (i = 1; i <= arr -> length; i ++) {
sdata (a, 1, i) = *(int *) ptr;
ptr += arr -> elt_size;
}
RecycleData (d);
d = coerced;
break;
case T_Byte:
CreateData (coerced, NULL, NULL, T_Matrix, 1, arr -> length);
a = D_Matrix (coerced);
ptr = (char *) arr -> ptr + arr -> elt_size;
for (i = 1; i <= arr -> length; i ++) {
sdata (a, 1, i) = *(char *) ptr;
ptr += arr -> elt_size;
}
RecycleData (d);
d = coerced;
break;
case T_Double:
CreateData (coerced, NULL, NULL, T_Matrix, 1, arr -> length);
a = D_Matrix (coerced);
ptr = (char *) arr -> ptr + arr -> elt_size;
for (i = 1; i <= arr -> length; i ++) {
sdata (a, 1, i) = *(double *) ptr;
ptr += arr -> elt_size;
}
RecycleData (d);
d = coerced;
break;
default:
break;
}
}
switch (D_Type (d)) {
/* A string can be converted to a double, integer, or byte, if the
entire string is numeric. */
case T_String:
switch (type) {
case T_Double:
data [count].dval = strtod (*D_String (d), &ptr);
while (*ptr) if (!isspace (*ptr ++)) return d;
RecycleData (d);
d = &array [count];
D_Type (d) = T_Double;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_Double (d) = &data [count].dval;
break;
case T_Int:
data [count].ival = strtol (*D_String (d), &ptr, 10);
while (*ptr) if (!isspace (*ptr ++)) return d;
RecycleData (d);
d = &array [count];
D_Type (d) = T_Int;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_Int (d) = &data [count].ival;
break;
case T_Byte:
data [count].bval = strtol (*D_String (d), &ptr, 10);
while (*ptr) if (!isspace (*ptr ++)) return d;
RecycleData (d);
d = &array [count];
D_Type (d) = T_Byte;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_Byte (d) = &data [count].bval;
break;
default:
break;
}
break;
/* A double can be converted to a string, integer, or byte. */
case T_Double:
switch (type) {
case T_String:
sprintf (strings [count], "%g", *D_Double (d));
data [count].sval = strings [count];
RecycleData (d);
d = &array [count];
D_Type (d) = T_String;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_String (d) = &data [count].sval;
break;
case T_Int:
data [count].ival = *D_Double (d);
RecycleData (d);
d = &array [count];
D_Type (d) = T_Int;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_Int (d) = &data [count].ival;
break;
case T_Byte:
data [count].bval = *D_Double (d);
RecycleData (d);
d = &array [count];
D_Type (d) = T_Byte;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_Byte (d) = &data [count].bval;
break;
default:
break;
}
break;
/* An integer can be converted to a string, double, or byte. */
case T_Int:
switch (type) {
case T_String:
sprintf (strings [count], "%d", *D_Int (d));
data [count].sval = strings [count];
RecycleData (d);
d = &array [count];
D_Type (d) = T_String;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_String (d) = &data [count].sval;
break;
case T_Double:
data [count].dval = *D_Int (d);
RecycleData (d);
d = &array [count];
D_Type (d) = T_Double;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_Double (d) = &data [count].dval;
break;
case T_Byte:
data [count].bval = *D_Byte (d);
RecycleData (d);
d = &array [count];
D_Type (d) = T_Byte;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_Byte (d) = &data [count].bval;
break;
default:
break;
}
break;
/* A byte can be converted to a string, double, or integer. */
case T_Byte:
switch (type) {
case T_String:
sprintf (strings [count], "%d", *D_Byte (d));
data [count].sval = strings [count];
RecycleData (d);
d = &array [count];
D_Type (d) = T_String;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_String (d) = &data [count].sval;
break;
case T_Double:
data [count].dval = *D_Byte (d);
RecycleData (d);
d = &array [count];
D_Type (d) = T_Double;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_Double (d) = &data [count].dval;
break;
case T_Int:
data [count].ival = *D_Byte (d);
RecycleData (d);
d = &array [count];
D_Type (d) = T_Int;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_Int (d) = &data [count].ival;
break;
default:
break;
}
break;
/* A matrix can be converted to a string, integer, or byte if it
consists of a single element. */
case T_Matrix:
a = D_Matrix (d);
if (Mrows (a) == 1 && Mcols (a) == 1)
switch (type) {
case T_String:
sprintf (strings [count], "%g", mdata (a, 1, 1));
data [count].sval = strings [count];
RecycleData (d);
d = &array [count];
D_Type (d) = T_String;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_String (d) = &data [count].sval;
break;
case T_Double:
data [count].dval = mdata (a, 1, 1);
RecycleData (d);
d = &array [count];
D_Type (d) = T_Double;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_Double (d) = &data [count].dval;
break;
case T_Int:
data [count].ival = mdata (a, 1, 1);
RecycleData (d);
d = &array [count];
D_Type (d) = T_Int;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_Int (d) = &data [count].ival;
break;
case T_Byte:
data [count].bval = mdata (a, 1, 1);
RecycleData (d);
d = &array [count];
D_Type (d) = T_Byte;
D_Temp (d) = F_False;
D_Trapped (d) = F_False;
D_Byte (d) = &data [count].bval;
break;
default:
break;
}
default:
break;
}
return d;
}
/************************************************************************
* Function: CoerceToArray *
* *
* Description: Coerces the data of a descriptor to an array. *
************************************************************************/
descriptor *CoerceToArray (d, type)
descriptor *d;
int type;
{
Matrix a;
char *ptr;
int handler;
descriptor *arr;
double value;
unsigned i;
unsigned nc;
unsigned nr;
count = (count + 1) % NumStatic;
handler = AddTrap (strict);
arr = &array [count];
switch (D_Type (d)) {
case T_Int:
value = *D_Int (d);
switch (type) {
case T_Int:
RecycleData (d);
ptr = (char *) Allocate (int, 2);
CreateData (d, NULL, NULL, T_Array, ptr, type, 1, handler);
((int *) ptr) [1] = value;
D_Array (d) -> temp = F_True;
break;
case T_Byte:
RecycleData (d);
ptr = (char *) Allocate (char, 2);
CreateData (d, NULL, NULL, T_Array, ptr, type, 1, handler);
((char *) ptr) [1] = value;
D_Array (d) -> temp = F_True;
break;
case T_Double:
RecycleData (d);
ptr = (char *) Allocate (double, 2);
CreateData (d, NULL, NULL, T_Array, ptr, type, 1, handler);
((double *) ptr) [1] = value;
D_Array (d) -> temp = F_True;
break;
default:
break;
}
break;
case T_Byte:
value = *D_Byte (d);
switch (type) {
case T_Int:
RecycleData (d);
ptr = (char *) Allocate (int, 2);
CreateData (d, NULL, NULL, T_Array, ptr, type, 1, handler);
((int *) ptr) [1] = value;
D_Array (d) -> temp = F_True;
break;
case T_Byte:
RecycleData (d);
ptr = (char *) Allocate (char, 2);
CreateData (d, NULL, NULL, T_Array, ptr, type, 1, handler);
((char *) ptr) [1] = value;
D_Array (d) -> temp = F_True;
break;
case T_Double:
RecycleData (d);
ptr = (char *) Allocate (double, 2);
CreateData (d, NULL, NULL, T_Array, ptr, type, 1, handler);
((double *) ptr) [1] = value;
D_Array (d) -> temp = F_True;
break;
default:
break;
}
break;
case T_Double:
value = *D_Double (d);
switch (type) {
case T_Int:
RecycleData (d);
ptr = (char *) Allocate (int, 2);
CreateData (d, NULL, NULL, T_Array, ptr, type, 1, handler);
((int *) ptr) [1] = value;
D_Array (d) -> temp = F_True;
break;
case T_Byte:
RecycleData (d);
ptr = (char *) Allocate (char, 2);
CreateData (d, NULL, NULL, T_Array, ptr, type, 1, handler);
((char *) ptr) [1] = value;
D_Array (d) -> temp = F_True;
break;
case T_Double:
RecycleData (d);
ptr = (char *) Allocate (double, 2);
CreateData (d, NULL, NULL, T_Array, ptr, type, 1, handler);
((double *) ptr) [1] = value;
D_Array (d) -> temp = F_True;
break;
default:
break;
}
break;
case T_String:
value = strtod (*D_String (d), &ptr);
while (*ptr) if (!isspace (*ptr ++)) return d;
switch (type) {
case T_Int:
RecycleData (d);
ptr = (char *) Allocate (int, 2);
CreateData (d, NULL, NULL, T_Array, ptr, type, 1, handler);
((int *) ptr) [1] = value;
D_Array (d) -> temp = F_True;
break;
case T_Byte:
RecycleData (d);
ptr = (char *) Allocate (char, 2);
CreateData (d, NULL, NULL, T_Array, ptr, type, 1, handler);
((char *) ptr) [1] = value;
D_Array (d) -> temp = F_True;
break;
case T_Double:
RecycleData (d);
ptr = (char *) Allocate (double, 2);
CreateData (d, NULL, NULL, T_Array, ptr, type, 1, handler);
((double *) ptr) [1] = value;
D_Array (d) -> temp = F_True;
break;
default:
break;
}
break;
case T_Matrix:
a = D_Matrix (d);
if (Mrows (a) == 1) {
nc = Mcols (a);
switch (type) {
case T_Int:
ptr = (char *) Allocate (int, nc + 1);
CreateData (arr, NULL, NULL, T_Array, ptr, type, nc, handler);
for (i = 1; i <= nc; i ++)
((int *) ptr) [i] = mdata (a, 1, i);
D_Array (arr) -> temp = F_True;
RecycleData (d);
d = arr;
break;
case T_Byte:
ptr = (char *) Allocate (char, nc + 1);
CreateData (arr, NULL, NULL, T_Array, ptr, type, nc, handler);
for (i = 1; i <= nc; i ++)
((char *) ptr) [i] = mdata (a, 1, i);
D_Array (arr) -> temp = F_True;
RecycleData (d);
d = arr;
break;
case T_Double:
ptr = (char *) Allocate (double, nc + 1);
CreateData (arr, NULL, NULL, T_Array, ptr, type, nc, handler);
for (i = 1; i <= nc; i ++)
((double *) ptr) [i] = mdata (a, 1, i);
D_Array (arr) -> temp = F_True;
RecycleData (d);
d = arr;
break;
default:
break;
}
} else if (Mcols (a) == 1) {
nr = Mrows (a);
switch (type) {
case T_Int:
ptr = (char *) Allocate (int, nr + 1);
CreateData (arr, NULL, NULL, T_Array, ptr, type, nr, handler);
for (i = 1; i <= nr; i ++)
((int *) ptr) [i] = mdata (a, i, 1);
D_Array (arr) -> temp = F_True;
RecycleData (d);
d = arr;
break;
case T_Byte:
ptr = (char *) Allocate (char, nr + 1);
CreateData (arr, NULL, NULL, T_Array, ptr, type, nr, handler);
for (i = 1; i <= nr; i ++)
((char *) ptr) [i] = mdata (a, i, 1);
D_Array (arr) -> temp = F_True;
RecycleData (d);
d = arr;
break;
case T_Double:
ptr = (char *) Allocate (double, nr + 1);
CreateData (arr, NULL, NULL, T_Array, ptr, type, nr, handler);
for (i = 1; i <= nr; i ++)
((double *) ptr) [i] = mdata (a, i, 1);
D_Array (arr) -> temp = F_True;
RecycleData (d);
d = arr;
break;
default:
break;
}
}
break;
default:
break;
}
return d;
}
syntax highlighted by Code2HTML, v. 0.9.1