/* 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 # 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; }