/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by the Board of Trustees of the University of Illinois. * * All rights reserved. * * * * terms governing use, modification, and redistribution, is contained in * * the files COPYING and Copyright.html. COPYING can be found at the root * * of the source code distribution tree; Copyright.html can be found at the * * root level of an installed copy of the electronic HDF5 document set and * * is linked from the top-level documents page. It can also be found at * * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define H5Z_PACKAGE /*suppress error about including H5Zpkg */ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5Iprivate.h" /* IDs */ #include "H5MMprivate.h" /* Memory management */ #include "H5Zpkg.h" /* Data filters */ #include "H5Vprivate.h" /* H5V_array_fill */ /* Token types */ typedef enum { H5Z_XFORM_ERROR, H5Z_XFORM_INTEGER, /* this represents an integer type in the data transform expression */ H5Z_XFORM_FLOAT, /* this represents a floating point type in the data transform expression */ H5Z_XFORM_SYMBOL, H5Z_XFORM_PLUS, H5Z_XFORM_MINUS, H5Z_XFORM_MULT, H5Z_XFORM_DIVIDE, H5Z_XFORM_LPAREN, H5Z_XFORM_RPAREN, H5Z_XFORM_END } H5Z_token_type; typedef struct { unsigned int num_ptrs; void** ptr_dat_val; } H5Z_datval_ptrs; /* Used to represent values in transform expression */ typedef union { void *dat_val; long int_val; double float_val; } H5Z_num_val; typedef struct H5Z_node { struct H5Z_node *lchild; struct H5Z_node *rchild; H5Z_token_type type; H5Z_num_val value; } H5Z_node; struct H5Z_data_xform_t { char* xform_exp; struct H5Z_node* parse_root; H5Z_datval_ptrs* dat_val_pointers; }; typedef struct result { H5Z_token_type type; H5Z_num_val value; } H5Z_result; /* The token */ typedef struct { const char *tok_expr; /* Holds the original expression */ /* Current token values */ H5Z_token_type tok_type; /* The type of the current token */ const char *tok_begin; /* The beginning of the current token */ const char *tok_end; /* The end of the current token */ /* Previous token values */ H5Z_token_type tok_last_type; /* The type of the last token */ const char *tok_last_begin; /* The beginning of the last token */ const char *tok_last_end; /* The end of the last token */ } H5Z_token; /* Local function prototypes */ static H5Z_token *H5Z_get_token(H5Z_token *current); static H5Z_node *H5Z_parse_expression(H5Z_token *current, H5Z_datval_ptrs* dat_val_pointers); static H5Z_node *H5Z_parse_term(H5Z_token *current, H5Z_datval_ptrs* dat_val_pointers); static H5Z_node *H5Z_parse_factor(H5Z_token *current, H5Z_datval_ptrs* dat_val_pointers); static H5Z_node *H5Z_new_node(H5Z_token_type type); static void H5Z_do_op(H5Z_node* tree); static hid_t H5Z_xform_find_type(const H5T_t* type); static herr_t H5Z_xform_eval_full(H5Z_node *tree, const size_t array_size, const hid_t array_type, H5Z_result* res); static void H5Z_xform_destroy_parse_tree(H5Z_node *tree); static void* H5Z_xform_parse(const char *expression, H5Z_datval_ptrs* dat_val_pointers); static void* H5Z_xform_copy_tree(H5Z_node* tree, H5Z_datval_ptrs* dat_val_pointers, H5Z_datval_ptrs* new_dat_val_pointers); static void H5Z_xform_reduce_tree(H5Z_node* tree); #ifdef H5Z_XFORM_DEBUG static void H5Z_XFORM_DEBUG(H5Z_node *tree); static void H5Z_print(H5Z_node *tree, FILE *stream); #endif /* H5Z_XFORM_DEBUG */ #define H5Z_XFORM_DO_OP1(RESL,RESR,TYPE,OP,SIZE) \ { \ if( (((RESL).type == H5Z_XFORM_SYMBOL) && ((RESR).type != H5Z_XFORM_SYMBOL)) || (((RESR).type == H5Z_XFORM_SYMBOL) && ((RESL).type != H5Z_XFORM_SYMBOL))) \ { \ size_t u; \ TYPE* p; \ double tree_val; \ \ if((RESL).type == H5Z_XFORM_SYMBOL) \ { \ tree_val = ((RESR).type==H5Z_XFORM_INTEGER ? (double)(RESR).value.int_val : (RESR).value.float_val); \ p = (TYPE*)(RESL).value.dat_val; \ } \ else \ { \ tree_val = ((RESL).type==H5Z_XFORM_INTEGER ? (double)(RESL).value.int_val : (RESL).value.float_val); \ p = (TYPE*)(RESR).value.dat_val; \ } \ \ for(u=0; u<(SIZE); u++) \ *p++ OP tree_val; \ } \ else if( ((RESL).type == H5Z_XFORM_SYMBOL) && ((RESR).type==H5Z_XFORM_SYMBOL)) \ { \ size_t u; \ TYPE* pl = (TYPE*)(RESL).value.dat_val; \ TYPE* pr = (TYPE*)(RESR).value.dat_val; \ \ for(u=0; u<(SIZE); u++) \ *pl++ OP *pr++; \ } \ else \ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Unexpected type conversion operation") \ \ } /* Due to the undefined nature of embedding macros/conditionals within macros, we employ * this clever little hack. We always compile in the code for the type conversion, even if * it isn't supported in the compiler. To avoid errors, we define ULLONG_TO_FP_XFORM_TYPE_OP_ERROR on * unsupported compilers, which will cause the code to execute HGOTO_ERROR and skip the code * that does the actual conversion */ #ifndef H5_ULLONG_TO_FP_CAST_WORKS #define H5Z_XFORM_ULL_DO_OP1(RESL,RESR,TYPE,OP,SIZE) \ { \ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Cannot convert from unsigned long long to double: required for data transform") \ } #else #define H5Z_XFORM_ULL_DO_OP1(RESL,RESR,TYPE,OP,SIZE) \ H5Z_XFORM_DO_OP1(RESL,RESR,TYPE,OP,SIZE) #endif /* Windows Intel 8.1 compiler has error converting long long to double. * Hard code it in. */ #ifndef H5_LLONG_TO_FP_CAST_WORKS #define H5Z_XFORM_LL_DO_OP1(RESL,RESR,TYPE,OP,SIZE) \ { \ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Cannot convert from long long to double: required for data transform") \ } #else #define H5Z_XFORM_LL_DO_OP1(RESL,RESR,TYPE,OP,SIZE) \ H5Z_XFORM_DO_OP1(RESL,RESR,TYPE,OP,SIZE) #endif #define H5Z_XFORM_TYPE_OP(RESL,RESR,TYPE,OP,SIZE) \ { \ if((TYPE) == H5T_NATIVE_CHAR) \ H5Z_XFORM_DO_OP1((RESL), (RESR), char, OP, (SIZE)) \ else if((TYPE) == H5T_NATIVE_UCHAR) \ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned char, OP, (SIZE)) \ else if((TYPE) == H5T_NATIVE_SCHAR) \ H5Z_XFORM_DO_OP1((RESL), (RESR), signed char, OP, (SIZE)) \ else if((TYPE) == H5T_NATIVE_SHORT) \ H5Z_XFORM_DO_OP1((RESL), (RESR), short, OP, (SIZE)) \ else if((TYPE) == H5T_NATIVE_USHORT) \ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned short, OP, (SIZE)) \ else if((TYPE) == H5T_NATIVE_INT) \ H5Z_XFORM_DO_OP1((RESL), (RESR), int, OP, (SIZE)) \ else if((TYPE) == H5T_NATIVE_UINT) \ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned int, OP, (SIZE)) \ else if((TYPE) == H5T_NATIVE_LONG) \ H5Z_XFORM_DO_OP1((RESL), (RESR), long, OP, (SIZE)) \ else if((TYPE) == H5T_NATIVE_ULONG) \ H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long, OP, (SIZE)) \ else if((TYPE) == H5T_NATIVE_LLONG) \ H5Z_XFORM_LL_DO_OP1((RESL), (RESR), long_long, OP, (SIZE)) \ else if((TYPE) == H5T_NATIVE_ULLONG) \ H5Z_XFORM_ULL_DO_OP1((RESL), (RESR), unsigned long_long, OP, (SIZE)) \ else if((TYPE) == H5T_NATIVE_FLOAT) \ H5Z_XFORM_DO_OP1((RESL), (RESR), float, OP, (SIZE)) \ else if((TYPE) == H5T_NATIVE_DOUBLE) \ H5Z_XFORM_DO_OP1((RESL), (RESR), double, OP, (SIZE)) \ else if((TYPE) == H5T_NATIVE_LDOUBLE) \ H5Z_XFORM_DO_OP1((RESL), (RESR), long double, OP, (SIZE)) \ } #define H5Z_XFORM_DO_OP3(OP) \ { \ if((tree->lchild->type == H5Z_XFORM_INTEGER) && (tree->rchild->type==H5Z_XFORM_INTEGER)) \ { \ tree->type = H5Z_XFORM_INTEGER; \ tree->value.int_val = tree->lchild->value.int_val OP tree->rchild->value.int_val; \ H5MM_xfree(tree->lchild); \ H5MM_xfree(tree->rchild); \ tree->lchild = NULL; \ tree->rchild = NULL; \ } \ else if( ( (tree->lchild->type == H5Z_XFORM_FLOAT) || (tree->lchild->type == H5Z_XFORM_INTEGER)) && \ ( (tree->rchild->type == H5Z_XFORM_FLOAT) || (tree->rchild->type == H5Z_XFORM_INTEGER))) \ { \ tree->type = H5Z_XFORM_FLOAT; \ tree->value.float_val = ((tree->lchild->type == H5Z_XFORM_FLOAT) ? tree->lchild->value.float_val : (double)tree->lchild->value.int_val) OP \ ((tree->rchild->type == H5Z_XFORM_FLOAT) ? tree->rchild->value.float_val : (double)tree->rchild->value.int_val); \ H5MM_xfree(tree->lchild); \ H5MM_xfree(tree->rchild); \ tree->lchild = NULL; \ tree->rchild = NULL; \ } \ } #define H5Z_XFORM_DO_OP4(TYPE) \ { \ if ((ret_value = (H5Z_node*) H5MM_malloc(sizeof(H5Z_node))) == NULL) \ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree") \ else \ { \ ret_value->type = (TYPE); \ ret_value->lchild = (H5Z_node*) H5Z_xform_copy_tree(tree->lchild, dat_val_pointers, new_dat_val_pointers); \ ret_value->rchild = (H5Z_node*) H5Z_xform_copy_tree(tree->rchild, dat_val_pointers, new_dat_val_pointers); \ } \ } #define H5Z_XFORM_DO_OP5(TYPE, SIZE) \ { \ TYPE val = ((tree->type == H5Z_XFORM_INTEGER) ? (TYPE)tree->value.int_val : (TYPE)tree->value.float_val); \ H5V_array_fill(array, &val, sizeof(TYPE), (SIZE)); \ } /* * Programmer: Bill Wendling * 25. August 2003 */ /* * This is the context-free grammar for our expressions: * * expr := term | term '+ term | term '-' term * term := factor | factor '*' factor | factor '/' factor * factor := number | * symbol | * '-' factor | // unary minus * '+' factor | // unary plus * '(' expr ')' * symbol := [a-zA-Z][a-zA-Z0-9]* * number := H5Z_XFORM_INTEGER | FLOAT * // H5Z_XFORM_INTEGER is a C long int * // FLOAT is a C double */ /*------------------------------------------------------------------------- * Function: H5Z_unget_token * Purpose: Rollback the H5Z_token to the previous H5Z_token retrieved. There * should only need to be one level of rollback necessary * for our grammar. * Return: Always succeeds. * Programmer: Bill Wendling * 26. August 2003 * Modifications: * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs * *------------------------------------------------------------------------- */ static void H5Z_unget_token(H5Z_token *current) { /* check args */ assert(current); FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5Z_unget_token) current->tok_type = current->tok_last_type; current->tok_begin = current->tok_last_begin; current->tok_end = current->tok_last_end; FUNC_LEAVE_NOAPI_VOID } /*------------------------------------------------------------------------- * Function: H5Z_get_token * Purpose: Determine what the next valid H5Z_token is in the expression * string. The current position within the H5Z_token string is * kept internal to the H5Z_token and handled by this and the * unget_H5Z_token function. * Return: Succeess: The passed in H5Z_token with a valid tok_type * field. * Failure: The passed in H5Z_token but with the tok_type * field set to ERROR. * Programmer: Bill Wendling * 26. August 2003 * Modifications: * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs *------------------------------------------------------------------------- */ static H5Z_token * H5Z_get_token(H5Z_token *current) { void* ret_value=current; FUNC_ENTER_NOAPI(H5Z_get_token, NULL) /* check args */ assert(current); /* Save the last position for possible ungets */ current->tok_last_type = current->tok_type; current->tok_last_begin = current->tok_begin; current->tok_last_end = current->tok_end; current->tok_begin = current->tok_end; while (current->tok_begin[0] != '\0') { if (isspace(current->tok_begin[0])) { /* ignore whitespace */ } else if (isdigit(current->tok_begin[0]) || current->tok_begin[0] == '.') { current->tok_end = current->tok_begin; /* * H5Z_XFORM_INTEGER := digit-sequence * digit-sequence := digit | digit digit-sequence * digit := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 */ if (current->tok_end[0] != '.') { /* is number */ current->tok_type = H5Z_XFORM_INTEGER; while (isdigit(current->tok_end[0])) ++current->tok_end; } /* * float := digit-sequence exponent | * dotted-digits exponent? * dotted-digits := digit-sequence '.' digit-sequence? | * '.' digit-sequence * exponent := [Ee] [-+]? digit-sequence */ if (current->tok_end[0] == '.' || current->tok_end[0] == 'e' || current->tok_end[0] == 'E') { current->tok_type = H5Z_XFORM_FLOAT; if (current->tok_end[0] == '.') do { ++current->tok_end; } while (isdigit(current->tok_end[0])); if (current->tok_end[0] == 'e' || current->tok_end[0] == 'E') { ++current->tok_end; if (current->tok_end[0] == '-' || current->tok_end[0] == '+') ++current->tok_end; if (!isdigit(current->tok_end[0])) { current->tok_type = H5Z_XFORM_ERROR; HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, current, "Invalidly formatted floating point number") } while (isdigit(current->tok_end[0])) ++current->tok_end; } /* Check that this is a properly formatted numerical value */ if (isalpha(current->tok_end[0]) || current->tok_end[0] == '.') { current->tok_type = H5Z_XFORM_ERROR; HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, current, "Invalidly formatted floating point number") } } break; } else if (isalpha(current->tok_begin[0])) { /* is symbol */ current->tok_type = H5Z_XFORM_SYMBOL; current->tok_end = current->tok_begin; while (isalnum(current->tok_end[0])) ++current->tok_end; break; } else { /* should be +, -, *, /, (, or ) */ switch (current->tok_begin[0]) { case '+': current->tok_type = H5Z_XFORM_PLUS; break; case '-': current->tok_type = H5Z_XFORM_MINUS; break; case '*': current->tok_type = H5Z_XFORM_MULT; break; case '/': current->tok_type = H5Z_XFORM_DIVIDE; break; case '(': current->tok_type = H5Z_XFORM_LPAREN; break; case ')': current->tok_type = H5Z_XFORM_RPAREN; break; default: current->tok_type = H5Z_XFORM_ERROR; HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, current, "Unknown H5Z_token in data transform expression ") } current->tok_end = current->tok_begin + 1; break; } ++current->tok_begin; } if (current->tok_begin[0] == '\0') current->tok_type = H5Z_XFORM_END; HGOTO_DONE(current); done: FUNC_LEAVE_NOAPI(ret_value) } /*------------------------------------------------------------------------- * Function: H5Z_xform_destroy_parse_tree * Purpose: Recursively destroys the expression tree. * Return: Nothing * Programmer: Bill Wendling * 25. August 2003 * Modifications: * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs * *------------------------------------------------------------------------- */ void H5Z_xform_destroy_parse_tree(H5Z_node *tree) { FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5Z_xform_destroy_parse_tree) if (tree) { H5Z_xform_destroy_parse_tree(tree->lchild); H5Z_xform_destroy_parse_tree(tree->rchild); H5MM_xfree(tree); tree = NULL; } FUNC_LEAVE_NOAPI_VOID } /*------------------------------------------------------------------------- * Function: H5Z_parse * Purpose: Entry function for parsing the expression string. * Return: Success: Valid H5Z_node ptr to an expression tree. * NULLure: NULL * Programmer: Bill Wendling * 26. August 2003 * Modifications: * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs * *------------------------------------------------------------------------- */ void * H5Z_xform_parse(const char *expression, H5Z_datval_ptrs* dat_val_pointers) { H5Z_token tok; void* ret_value; FUNC_ENTER_NOAPI_NOFUNC(H5Z_xform_parse) if (!expression) HGOTO_DONE(NULL) /* Set up the initial H5Z_token for parsing */ tok.tok_expr = tok.tok_begin = tok.tok_end = expression; ret_value = (void*)H5Z_parse_expression(&tok, dat_val_pointers); H5Z_xform_reduce_tree((H5Z_node*)ret_value); done: FUNC_LEAVE_NOAPI(ret_value) } /*------------------------------------------------------------------------- * Function: H5Z_parse_expression * Purpose: Beginning of the recursive descent parser to parse the * expression. An expression is: * * expr := term | term '+' term | term '-' term * * Return: Success: Valid H5Z_node ptr to expression tree * NULLure: NULL * Programmer: Bill Wendling * 26. August 2003 * Modifications: * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs * *------------------------------------------------------------------------- */ static H5Z_node * H5Z_parse_expression(H5Z_token *current, H5Z_datval_ptrs* dat_val_pointers) { H5Z_node *expr; void* ret_value; FUNC_ENTER_NOAPI_NOINIT(H5Z_parse_expression) expr = H5Z_parse_term(current, dat_val_pointers); for (;;) { H5Z_node *new_node; current = H5Z_get_token(current); switch (current->tok_type) { case H5Z_XFORM_PLUS: new_node = H5Z_new_node(H5Z_XFORM_PLUS); if (!new_node) { H5Z_xform_destroy_parse_tree(expr); HGOTO_DONE(expr) } new_node->lchild = expr; new_node->rchild = H5Z_parse_term(current, dat_val_pointers); if (!new_node->rchild) { H5Z_xform_destroy_parse_tree(new_node); HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") } expr = new_node; break; case H5Z_XFORM_MINUS: new_node = H5Z_new_node(H5Z_XFORM_MINUS); if (!new_node) { H5Z_xform_destroy_parse_tree(expr); HGOTO_DONE(expr) } new_node->lchild = expr; new_node->rchild = H5Z_parse_term(current, dat_val_pointers); if (!new_node->rchild) { H5Z_xform_destroy_parse_tree(new_node); HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") } expr = new_node; break; case H5Z_XFORM_RPAREN: H5Z_unget_token(current); HGOTO_DONE(expr) case H5Z_XFORM_END: HGOTO_DONE(expr) default: H5Z_xform_destroy_parse_tree(expr); HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") } } done: FUNC_LEAVE_NOAPI(ret_value) } /*------------------------------------------------------------------------- * Function: H5Z_parse_term * Purpose: Parses a term in our expression language. A term is: * * term := factor | factor '*' factor | factor '/' factor * * Return: Success: Valid H5Z_node ptr to expression tree * NULLure: NULL * Programmer: Bill Wendling * 26. August 2003 * Modifications: * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs * *------------------------------------------------------------------------- */ static H5Z_node * H5Z_parse_term(H5Z_token *current, H5Z_datval_ptrs* dat_val_pointers) { H5Z_node *term = NULL; void* ret_value; FUNC_ENTER_NOAPI(H5Z_parse_term, NULL); term = H5Z_parse_factor(current, dat_val_pointers); for (;;) { H5Z_node *new_node; current = H5Z_get_token(current); switch (current->tok_type) { case H5Z_XFORM_MULT: new_node = H5Z_new_node(H5Z_XFORM_MULT); if (!new_node) { H5Z_xform_destroy_parse_tree(term); HGOTO_DONE(term) } new_node->lchild = term; new_node->rchild = H5Z_parse_factor(current, dat_val_pointers); if (!new_node->rchild) { H5Z_xform_destroy_parse_tree(term); HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") } term = new_node; break; case H5Z_XFORM_DIVIDE: new_node = H5Z_new_node(H5Z_XFORM_DIVIDE); if (!new_node) { H5Z_xform_destroy_parse_tree(term); HGOTO_DONE(term) } new_node->lchild = term; new_node->rchild = H5Z_parse_factor(current, dat_val_pointers); term = new_node; if (!new_node->rchild) { H5Z_xform_destroy_parse_tree(term); HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") } break; case H5Z_XFORM_RPAREN: H5Z_unget_token(current); HGOTO_DONE(term) case H5Z_XFORM_END: HGOTO_DONE(term) default: H5Z_unget_token(current); HGOTO_DONE(term) } } done: FUNC_LEAVE_NOAPI(ret_value) } /*------------------------------------------------------------------------- * Function: H5Z_parse_factor * Purpose: Parses a factor in our expression language. A factor is: * * factor := number | // C long or double * symbol | // C identifier * '-' factor | // unary minus * '+' factor | // unary plus * '(' expr ')' * * Return: Success: Valid H5Z_node ptr to expression tree * NULLure: NULL * Programmer: Bill Wendling * 26. August 2003 * Modifications: * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs * *------------------------------------------------------------------------- */ static H5Z_node * H5Z_parse_factor(H5Z_token *current, H5Z_datval_ptrs* dat_val_pointers) { H5Z_node *factor=NULL; H5Z_node *new_node; void* ret_value; FUNC_ENTER_NOAPI(H5Z_parse_factor, NULL); current = H5Z_get_token(current); switch (current->tok_type) { case H5Z_XFORM_INTEGER: factor = H5Z_new_node(H5Z_XFORM_INTEGER); if (!factor) HGOTO_DONE(factor) sscanf(current->tok_begin, "%ld", &factor->value.int_val); break; case H5Z_XFORM_FLOAT: factor = H5Z_new_node(H5Z_XFORM_FLOAT); if (!factor) HGOTO_DONE(factor) sscanf(current->tok_begin, "%lf", &factor->value.float_val); break; case H5Z_XFORM_SYMBOL: factor = H5Z_new_node(H5Z_XFORM_SYMBOL); if (!factor) HGOTO_DONE(factor) factor->value.dat_val = &(dat_val_pointers->ptr_dat_val[dat_val_pointers->num_ptrs]); dat_val_pointers->num_ptrs++; break; case H5Z_XFORM_LPAREN: factor = H5Z_parse_expression(current, dat_val_pointers); if (!factor) HGOTO_DONE(factor) current = H5Z_get_token(current); if (current->tok_type != H5Z_XFORM_RPAREN) { H5Z_xform_destroy_parse_tree(factor); HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Syntax error in data transform expression") } break; case H5Z_XFORM_RPAREN: /* We shouldn't see a ) right now */ H5Z_xform_destroy_parse_tree(factor); HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Syntax error: unexpected ')' ") case H5Z_XFORM_PLUS: /* unary + */ new_node = H5Z_parse_factor(current, dat_val_pointers); if (new_node) { if (new_node->type != H5Z_XFORM_INTEGER && new_node->type != H5Z_XFORM_FLOAT && new_node->type != H5Z_XFORM_SYMBOL) { H5Z_xform_destroy_parse_tree(new_node); H5Z_xform_destroy_parse_tree(factor); HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") } factor = new_node; new_node = H5Z_new_node(H5Z_XFORM_PLUS); if (!new_node) { H5Z_xform_destroy_parse_tree(factor); HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") } new_node->rchild = factor; factor = new_node; } else { H5Z_xform_destroy_parse_tree(factor); HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") } break; case H5Z_XFORM_MINUS: /* unary - */ new_node = H5Z_parse_factor(current, dat_val_pointers); if (new_node) { if (new_node->type != H5Z_XFORM_INTEGER && new_node->type != H5Z_XFORM_FLOAT && new_node->type != H5Z_XFORM_SYMBOL) { H5Z_xform_destroy_parse_tree(new_node); H5Z_xform_destroy_parse_tree(factor); HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") } factor = new_node; new_node = H5Z_new_node(H5Z_XFORM_MINUS); if (!new_node) { H5Z_xform_destroy_parse_tree(factor); HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") } new_node->rchild = factor; factor = new_node; } else { H5Z_xform_destroy_parse_tree(factor); HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") } break; case H5Z_XFORM_END: break; default: HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Invalid token while parsing data transform expression") } /* Set return value */ ret_value=factor; done: FUNC_LEAVE_NOAPI(ret_value); } /*------------------------------------------------------------------------- * Function: H5Z_new_node * Purpose: Create and initilize a new H5Z_node structure. * Return: Success: Valid H5Z_node ptr * NULLure: NULL * Programmer: Bill Wendling * 26. August 2003 * Modifications: * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs * *------------------------------------------------------------------------- */ static H5Z_node * H5Z_new_node(H5Z_token_type type) { H5Z_node* new_node; FUNC_ENTER_NOAPI_NOFUNC(H5Z_new_node) new_node = H5MM_calloc(sizeof(H5Z_node)); assert(new_node); new_node->type = type; FUNC_LEAVE_NOAPI(new_node); } /*------------------------------------------------------------------------- * Function: H5Z_xform_eval * Purpose: If the transform is trivial, this function applies it. * Otherwise, it calls H5Z_xform_eval_full to do the full * transform. * Return: SUCCEED if transform applied succesfully, FAIL otherwise * Programmer: Leon Arber * 5/1/04 * Modifications: * *------------------------------------------------------------------------- */ herr_t H5Z_xform_eval(H5Z_data_xform_t *data_xform_prop, void* array, size_t array_size, const H5T_t *buf_type) { H5Z_node *tree; hid_t array_type; size_t i; H5Z_result res; herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(H5Z_xform_eval, FAIL) assert(data_xform_prop); tree=data_xform_prop->parse_root; /* Get the datatype ID for the buffer's type */ if( (array_type = H5Z_xform_find_type(buf_type)) < 0) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Cannot perform data transform on this type.") /*After this point, we're assured that the type of the array is handled by the eval code, so we no * longer have to check for valid types */ /* If it's a trivial data transform, perform it */ if( tree->type == H5Z_XFORM_INTEGER || tree->type == H5Z_XFORM_FLOAT) { if(array_type == H5T_NATIVE_CHAR) H5Z_XFORM_DO_OP5(char, array_size) else if(array_type == H5T_NATIVE_UCHAR) H5Z_XFORM_DO_OP5(unsigned char, array_size) else if(array_type == H5T_NATIVE_SCHAR) H5Z_XFORM_DO_OP5(signed char, array_size) else if(array_type == H5T_NATIVE_SHORT) H5Z_XFORM_DO_OP5(short, array_size) else if(array_type == H5T_NATIVE_USHORT) H5Z_XFORM_DO_OP5(unsigned short, array_size) else if( array_type == H5T_NATIVE_INT) H5Z_XFORM_DO_OP5(int, array_size) else if(array_type == H5T_NATIVE_UINT) H5Z_XFORM_DO_OP5(unsigned int, array_size) else if(array_type == H5T_NATIVE_LONG) H5Z_XFORM_DO_OP5(long, array_size) else if(array_type == H5T_NATIVE_ULONG) H5Z_XFORM_DO_OP5(unsigned long, array_size) else if(array_type == H5T_NATIVE_LLONG) H5Z_XFORM_DO_OP5(long_long, array_size) else if(array_type == H5T_NATIVE_ULLONG) H5Z_XFORM_DO_OP5(unsigned long_long, array_size) else if(array_type == H5T_NATIVE_FLOAT) H5Z_XFORM_DO_OP5(float, array_size) else if(array_type == H5T_NATIVE_DOUBLE) H5Z_XFORM_DO_OP5(double, array_size) else if(array_type == H5T_NATIVE_LDOUBLE) H5Z_XFORM_DO_OP5(long double, array_size) } /* Otherwise, do the full data transform */ else { /* Optimization for linear transform: */ if(data_xform_prop->dat_val_pointers->num_ptrs == 1) data_xform_prop->dat_val_pointers->ptr_dat_val[0] = array; /* If it's a quadratic transform, we have no choice but to store multiple copies of the data */ else { for(i=0; idat_val_pointers->num_ptrs; i++) { if( (data_xform_prop->dat_val_pointers->ptr_dat_val[i] = (void*)HDmalloc(array_size*H5Tget_size(array_type))) == NULL) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "Ran out of memory trying to allocate space for data in data transform") HDmemcpy(data_xform_prop->dat_val_pointers->ptr_dat_val[i], array, array_size*H5Tget_size(array_type)); } } if(H5Z_xform_eval_full(tree, array_size, array_type, &res) < 0) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error while performing data transform") else { HDmemcpy(array, res.value.dat_val, array_size*H5Tget_size(array_type)); /* Free the temporary arrays we used */ if(data_xform_prop->dat_val_pointers->num_ptrs > 1) { for(i=0; idat_val_pointers->num_ptrs; i++) HDfree(data_xform_prop->dat_val_pointers->ptr_dat_val[i]); } } } done: if(ret_value < 0) { /* If we ran out of memory above copying the array for temp storage (which we easily can for * polynomial transforms of high order) we free those arrays which we already allocated */ if(data_xform_prop->dat_val_pointers->num_ptrs > 1) for(i=0; idat_val_pointers->num_ptrs; i++) if(data_xform_prop->dat_val_pointers->ptr_dat_val[i] != NULL) HDfree(data_xform_prop->dat_val_pointers->ptr_dat_val[i]); } FUNC_LEAVE_NOAPI(ret_value); } /*------------------------------------------------------------------------- * Function: H5Z_xform_eval_full * Purpose: Does a full evaluation of the parse tree contained in tree * and applies this transform to array. * Return: Nothing * Programmer: Leon Arber * 5/1/04 * Modifications: * * * Notes: In the case of a polynomial data transform (ie, the left and right subtree * are both of type H5Z_XFORM_SYMBOL), the convention is that the left hand side * will accumulate changes and, at the end, the new data will be copied from the lhs. *------------------------------------------------------------------------- */ static herr_t H5Z_xform_eval_full(H5Z_node *tree, const size_t array_size, const hid_t array_type, H5Z_result* res) { H5Z_result resl, resr; herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(H5Z_xform_eval_full, FAIL); /* check args */ assert(tree); if (tree->type == H5Z_XFORM_INTEGER) { res->type = H5Z_XFORM_INTEGER; res->value.int_val = tree->value.int_val; } else if (tree->type == H5Z_XFORM_FLOAT) { res->type = H5Z_XFORM_FLOAT; res->value.float_val = tree->value.float_val; } else if (tree->type == H5Z_XFORM_SYMBOL) { res->type = H5Z_XFORM_SYMBOL; /*since dat_val stores the address of the array which is really stored in the dat_val_pointers, * here we make dat_val store a pointer to the array itself instead of the address of it so that the * rest of the code below works normally. */ res->value.dat_val = *((void**)(tree->value.dat_val)); } else { if(H5Z_xform_eval_full(tree->lchild, array_size, array_type, &resl) < 0) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error while performing data transform") if(H5Z_xform_eval_full(tree->rchild, array_size, array_type, &resr) < 0) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error while performing data transform") res->type = H5Z_XFORM_SYMBOL; /* For each type of operation: * 1. See if "x" is on left hand side, right hand side, or if both sides are "x" * 2. Figure out what type of data we're going to be manipulating * 3. Do the operation on the data. */ switch (tree->type) { case H5Z_XFORM_PLUS: H5Z_XFORM_TYPE_OP(resl, resr, array_type, +=, array_size) break; case H5Z_XFORM_MINUS: H5Z_XFORM_TYPE_OP(resl, resr, array_type, -=, array_size) break; case H5Z_XFORM_MULT: H5Z_XFORM_TYPE_OP(resl, resr, array_type, *=, array_size) break; case H5Z_XFORM_DIVIDE: H5Z_XFORM_TYPE_OP(resl, resr, array_type, /=, array_size) break; default: HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Invalid expression tree") } /* The result stores a pointer to the new data */ /* So, if the left hand side got its data modified, the result stores a pointers * to the left hand side's data, ditto for rhs */ if(resl.type == H5Z_XFORM_SYMBOL) res->value.dat_val = resl.value.dat_val; else if(resr.type == H5Z_XFORM_SYMBOL) res->value.dat_val = resr.value.dat_val; else HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error during transform evaluation") } done: FUNC_LEAVE_NOAPI(ret_value) } /*------------------------------------------------------------------------- * Function: H5Z_find_type * Return: Native type of datatype that is passed in * Programmer: Leon Arber, 4/20/04 * Modifications: * * *------------------------------------------------------------------------- */ static hid_t H5Z_xform_find_type(const H5T_t* type) { hid_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NOINIT(H5Z_xform_find_type); assert(type); /* Check for SHORT type */ if((H5T_cmp(type, H5I_object_verify(H5T_NATIVE_SHORT,H5I_DATATYPE), FALSE ))==0) HGOTO_DONE(H5T_NATIVE_SHORT) /* Check for INT type */ else if((H5T_cmp(type, H5I_object_verify(H5T_NATIVE_INT,H5I_DATATYPE), FALSE))==0) HGOTO_DONE(H5T_NATIVE_INT) /* Check for LONG type */ else if((H5T_cmp(type, H5I_object_verify(H5T_NATIVE_LONG,H5I_DATATYPE), FALSE))==0) HGOTO_DONE(H5T_NATIVE_LONG) /* Check for LONGLONG type */ else if((H5T_cmp(type, H5I_object_verify(H5T_NATIVE_LLONG,H5I_DATATYPE), FALSE))==0) HGOTO_DONE(H5T_NATIVE_LLONG) /* Check for UCHAR type */ else if((H5T_cmp(type, H5I_object_verify(H5T_NATIVE_UCHAR,H5I_DATATYPE), FALSE))==0) HGOTO_DONE(H5T_NATIVE_UCHAR) /* Check for CHAR type */ else if((H5T_cmp(type, H5I_object_verify(H5T_NATIVE_CHAR,H5I_DATATYPE), FALSE))==0) HGOTO_DONE(H5T_NATIVE_CHAR) /* Check for SCHAR type */ else if((H5T_cmp(type, H5I_object_verify(H5T_NATIVE_SCHAR,H5I_DATATYPE), FALSE))==0) HGOTO_DONE(H5T_NATIVE_SCHAR) /* Check for USHORT type */ else if((H5T_cmp(type, H5I_object_verify(H5T_NATIVE_USHORT,H5I_DATATYPE), FALSE))==0) HGOTO_DONE(H5T_NATIVE_USHORT) /* Check for UINT type */ else if((H5T_cmp(type, H5I_object_verify(H5T_NATIVE_UINT,H5I_DATATYPE), FALSE))==0) HGOTO_DONE(H5T_NATIVE_UINT) /* Check for ULONG type */ else if((H5T_cmp(type, H5I_object_verify(H5T_NATIVE_ULONG,H5I_DATATYPE), FALSE))==0) HGOTO_DONE(H5T_NATIVE_ULONG) /* Check for ULONGLONG type */ else if((H5T_cmp(type, H5I_object_verify(H5T_NATIVE_ULLONG,H5I_DATATYPE), FALSE))==0) HGOTO_DONE(H5T_NATIVE_ULLONG) /* Check for FLOAT type */ else if((H5T_cmp(type, H5I_object_verify(H5T_NATIVE_FLOAT,H5I_DATATYPE), FALSE))==0) HGOTO_DONE(H5T_NATIVE_FLOAT) /* Check for DOUBLE type */ else if((H5T_cmp(type, H5I_object_verify(H5T_NATIVE_DOUBLE,H5I_DATATYPE), FALSE))==0) HGOTO_DONE(H5T_NATIVE_DOUBLE) /* Check for LONGDOUBLE type */ else if((H5T_cmp(type, H5I_object_verify(H5T_NATIVE_LDOUBLE,H5I_DATATYPE), FALSE))==0) HGOTO_DONE(H5T_NATIVE_LDOUBLE) else HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "could not find matching type"); done: FUNC_LEAVE_NOAPI(ret_value) } /*------------------------------------------------------------------------- * Function: H5Z_xform_copy_tree * Purpose: Makes a copy of the parse tree passed in. * Return: A pointer to a root for a new parse tree which is a copy * of the one passed in. * Programmer: Leon Arber * April 1, 2004. * Modifications: * *------------------------------------------------------------------------- */ void * H5Z_xform_copy_tree(H5Z_node* tree, H5Z_datval_ptrs* dat_val_pointers, H5Z_datval_ptrs* new_dat_val_pointers) { H5Z_node* ret_value=NULL; FUNC_ENTER_NOAPI(H5Z_xform_copy_tree, NULL) assert(tree); if(tree->type == H5Z_XFORM_INTEGER) { if ((ret_value = (H5Z_node*) H5MM_malloc(sizeof(H5Z_node))) == NULL) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree") else { ret_value -> type = H5Z_XFORM_INTEGER; ret_value ->value.int_val = tree->value.int_val; ret_value -> lchild = NULL; ret_value -> rchild = NULL; } } else if (tree->type == H5Z_XFORM_FLOAT) { if ((ret_value = (H5Z_node*) H5MM_malloc(sizeof(H5Z_node))) == NULL) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree") else { ret_value -> type = H5Z_XFORM_FLOAT; ret_value ->value.float_val = tree->value.float_val; ret_value -> lchild = NULL; ret_value -> rchild = NULL; } } else if(tree->type == H5Z_XFORM_SYMBOL) { if ((ret_value = (H5Z_node*) H5MM_malloc(sizeof(H5Z_node))) == NULL) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree") else { ret_value -> type = H5Z_XFORM_SYMBOL; ret_value -> value.dat_val = &(new_dat_val_pointers->ptr_dat_val[new_dat_val_pointers->num_ptrs]); new_dat_val_pointers->num_ptrs++; ret_value -> lchild = NULL; ret_value -> rchild = NULL; } } else if(tree->type == H5Z_XFORM_MULT) H5Z_XFORM_DO_OP4(H5Z_XFORM_MULT) else if(tree->type == H5Z_XFORM_PLUS) H5Z_XFORM_DO_OP4(H5Z_XFORM_PLUS) else if(tree->type == H5Z_XFORM_MINUS) H5Z_XFORM_DO_OP4(H5Z_XFORM_MINUS) else if(tree->type == H5Z_XFORM_DIVIDE) H5Z_XFORM_DO_OP4(H5Z_XFORM_DIVIDE) else HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error in parse tree while trying to copy") done: FUNC_LEAVE_NOAPI(ret_value) } /*------------------------------------------------------------------------- * Function: H5Z_xform_reduce_tree * Purpose: Simplifies parse tree passed in by performing any obvious * and trivial arithemtic calculations. * * Return: None. * Programmer: Leon Arber * April 1, 2004. * Modifications: * *------------------------------------------------------------------------- */ void H5Z_xform_reduce_tree(H5Z_node* tree) { FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5Z_xform_reduce_tree) if(tree) { if((tree->type == H5Z_XFORM_PLUS) || (tree->type == H5Z_XFORM_DIVIDE) ||(tree->type == H5Z_XFORM_MULT) ||(tree->type == H5Z_XFORM_MINUS)) { if(((tree->lchild->type == H5Z_XFORM_INTEGER) || (tree->lchild->type == H5Z_XFORM_FLOAT)) && ((tree->rchild->type == H5Z_XFORM_INTEGER) || (tree->rchild->type == H5Z_XFORM_FLOAT))) H5Z_do_op(tree); else { H5Z_xform_reduce_tree(tree->lchild); if(((tree->lchild->type == H5Z_XFORM_INTEGER) || (tree->lchild->type == H5Z_XFORM_FLOAT)) && ((tree->rchild->type == H5Z_XFORM_INTEGER) || (tree->rchild->type == H5Z_XFORM_FLOAT))) H5Z_do_op(tree); else { H5Z_xform_reduce_tree(tree->rchild); if(((tree->lchild->type == H5Z_XFORM_INTEGER) || (tree->lchild->type == H5Z_XFORM_FLOAT)) && ((tree->rchild->type == H5Z_XFORM_INTEGER) || (tree->rchild->type == H5Z_XFORM_FLOAT))) H5Z_do_op(tree); } } } } FUNC_LEAVE_NOAPI_VOID; } /*------------------------------------------------------------------------- * Function: H5Z_do_op * Purpose: If the root of the tree passed in points to a simple * arithmetic operation and the left and right subtrees are both * integer or floating point values, this function does that * operation, free the left and rigt subtrees, and replaces * the root with the result of the operation. * Return: None. * Programmer: Leon Arber * April 1, 2004. * Modifications: * *------------------------------------------------------------------------- */ static void H5Z_do_op(H5Z_node* tree) { FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5Z_do_op) if(tree->type == H5Z_XFORM_DIVIDE) H5Z_XFORM_DO_OP3(/) else if(tree->type == H5Z_XFORM_MULT) H5Z_XFORM_DO_OP3(*) else if(tree->type == H5Z_XFORM_PLUS) H5Z_XFORM_DO_OP3(+) else if(tree->type == H5Z_XFORM_MINUS) H5Z_XFORM_DO_OP3(-) FUNC_LEAVE_NOAPI_VOID; } /*------------------------------------------------------------------------- * Function: H5D_xform_create * * Purpose: Create a new data transform object from a string. * * Return: * Success: SUCCEED * Failure: FAIL * * Programmer: Quincey Koziol, koziol@ncsa.uiuc.edu * * Date: May 4, 2004 * * Comments: * * Modifications: * *------------------------------------------------------------------------- */ H5Z_data_xform_t * H5Z_xform_create(const char *expr) { H5Z_data_xform_t *data_xform_prop=NULL; H5Z_data_xform_t *ret_value; unsigned int i; unsigned int count = 0; FUNC_ENTER_NOAPI(H5Z_xform_create, NULL) assert(expr); /* Allocate space for the data transform information */ if((data_xform_prop = H5MM_calloc(sizeof(H5Z_data_xform_t)))==NULL) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate memory for data transform info") if((data_xform_prop->dat_val_pointers = HDmalloc(sizeof(H5Z_datval_ptrs))) == NULL) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate memory for data transform array storage") /* copy the user's string into the property */ if((data_xform_prop->xform_exp = H5MM_xstrdup(expr))==NULL) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate memory for data transform expression") /* Find the number of times "x" is used in this equation, and allocate room for storing that many points */ for(i=0; i 0) if((data_xform_prop->dat_val_pointers->ptr_dat_val = (void**) HDcalloc(count, sizeof(void**))) == NULL) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate memory for pointers in transform array") /* Initialize the num_ptrs field, which will be used to keep track of the number of copies * of the data we have for polynomial transforms */ data_xform_prop->dat_val_pointers->num_ptrs = 0; /* we generate the parse tree right here and store a poitner to its root in the property. */ if((data_xform_prop->parse_root = H5Z_xform_parse(expr, data_xform_prop->dat_val_pointers))==NULL) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to generate parse tree from expression") /* Sanity check * count should be the same num_ptrs */ if(count != data_xform_prop->dat_val_pointers->num_ptrs) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "error copying the parse tree, did not find correct number of \"variables\"") /* Assign return value */ ret_value=data_xform_prop; done: /* Clean up on error */ if(ret_value==NULL) { if(data_xform_prop) { if(data_xform_prop->parse_root) H5Z_xform_destroy_parse_tree(data_xform_prop->parse_root); if(data_xform_prop->xform_exp) H5MM_xfree(data_xform_prop->xform_exp); H5MM_xfree(data_xform_prop); } /* end if */ } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* H5Z_xform_create() */ /*------------------------------------------------------------------------- * Function: H5Z_xform_destroy * * Purpose: Destroy a data transform object. * * Return: * Success: SUCCEED * Failure: FAIL * * Programmer: Quincey Koziol, koziol@ncsa.uiuc.edu * * Date: May 4, 2004 * * Comments: * * Modifications: * *------------------------------------------------------------------------- */ herr_t H5Z_xform_destroy(H5Z_data_xform_t *data_xform_prop) { FUNC_ENTER_NOAPI_NOFUNC(H5Z_xform_destroy) if(data_xform_prop) { /* Destroy the parse tree */ H5Z_xform_destroy_parse_tree(data_xform_prop->parse_root); /* Free the expression */ H5MM_xfree(data_xform_prop->xform_exp); /* Free the pointers to the temp. arrays, if there are any */ if(data_xform_prop->dat_val_pointers->num_ptrs > 0) H5MM_xfree(data_xform_prop->dat_val_pointers->ptr_dat_val); /* Free the data storage struct */ H5MM_xfree(data_xform_prop->dat_val_pointers); /* Free the node */ H5MM_xfree(data_xform_prop); } /* end if */ FUNC_LEAVE_NOAPI(SUCCEED) } /* H5Z_xform_destroy() */ /*------------------------------------------------------------------------- * Function: H5Z_xform_copy * * Purpose: Clone a data transform object. * * Return: * Success: SUCCEED * Failure: FAIL * * Programmer: Quincey Koziol, koziol@ncsa.uiuc.edu * * Date: May 4, 2004 * * Comments: This is an "in-place" copy, since this routine gets called * after the top-level copy has been performed and this routine finishes * the "deep" part of the copy. * * Modifications: * *------------------------------------------------------------------------- */ herr_t H5Z_xform_copy(H5Z_data_xform_t **data_xform_prop) { unsigned int i; unsigned int count = 0; H5Z_data_xform_t *new_data_xform_prop=NULL; herr_t ret_value=SUCCEED; FUNC_ENTER_NOAPI(H5Z_xform_copy, FAIL) if(*data_xform_prop) { /* Allocate new node */ if((new_data_xform_prop = H5MM_calloc(sizeof(H5Z_data_xform_t)))==NULL) HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory for data transform info") /* Copy string */ if((new_data_xform_prop->xform_exp = H5MM_xstrdup((*data_xform_prop)->xform_exp))==NULL) HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory for data transform expression") if((new_data_xform_prop->dat_val_pointers = HDmalloc(sizeof(H5Z_datval_ptrs))) == NULL) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory for data transform array storage") /* Find the number of times "x" is used in this equation, and allocate room for storing that many points */ for(i=0; ixform_exp); i++) { if(isalpha(new_data_xform_prop->xform_exp[i])) count++; } if(count > 0) if((new_data_xform_prop->dat_val_pointers->ptr_dat_val = (void**) HDcalloc(count, sizeof(void**))) == NULL) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory for pointers in transform array") /* Zero out num_pointers prior to H5Z_xform_cop_tree call; that call will increment it to the right amount */ new_data_xform_prop->dat_val_pointers->num_ptrs = 0; /* Copy parse tree */ if((new_data_xform_prop->parse_root = (H5Z_node*)H5Z_xform_copy_tree((*data_xform_prop)->parse_root, (*data_xform_prop)->dat_val_pointers, new_data_xform_prop->dat_val_pointers)) == NULL) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "error copying the parse tree") /* Sanity check * count should be the same num_ptrs */ if(count != new_data_xform_prop->dat_val_pointers->num_ptrs) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "error copying the parse tree, did not find correct number of \"variables\"") /* Copy new information on top of old information */ *data_xform_prop=new_data_xform_prop; } /* end if */ done: /* Clean up on error */ if(ret_value<0) { if(new_data_xform_prop) { if(new_data_xform_prop->parse_root) H5Z_xform_destroy_parse_tree(new_data_xform_prop->parse_root); if(new_data_xform_prop->xform_exp) H5MM_xfree(new_data_xform_prop->xform_exp); H5MM_xfree(new_data_xform_prop); } /* end if */ } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* H5Z_xform_copy() */ /*------------------------------------------------------------------------- * Function: H5Z_xform_noop * * Purpose: Checks if a data transform will be performed * * Return: TRUE for no data transform, FALSE for a data transform * * Programmer: Quincey Koziol, koziol@ncsa.uiuc.edu * * Date: May 4, 2004 * * Comments: Can't fail * * Modifications: * *------------------------------------------------------------------------- */ hbool_t H5Z_xform_noop(const H5Z_data_xform_t *data_xform_prop) { hbool_t ret_value; FUNC_ENTER_NOAPI_NOFUNC(H5Z_xform_noop) ret_value=(data_xform_prop ? FALSE : TRUE); FUNC_LEAVE_NOAPI(ret_value) } /* H5Z_xform_noop() */ /*------------------------------------------------------------------------- * Function: H5Z_xform_extract_xform_str * * Purpose: Extracts the pointer to the data transform strings from the * data transform property.` * Return: * Pointer to a copy of the string in the data_xform property. * * Programmer: Leon Arber, larber@ncsa.uiuc.edu * * Date: Sept. 4, 2004 * * Modifications: * *------------------------------------------------------------------------- */ char * H5Z_xform_extract_xform_str(const H5Z_data_xform_t *data_xform_prop) { char* ret_value; FUNC_ENTER_NOAPI_NOFUNC(H5Z_xform_extract_xform_str) /* There should be no way that this can be NULL since the function * that calls this one checks to make sure it isn't before * pasing them */ assert(data_xform_prop); ret_value = data_xform_prop->xform_exp; FUNC_LEAVE_NOAPI(ret_value) } /* H5Z_xform_extract_xform_str() */