#include "niml_private.h"
/*-----------------------------------------------------------------------*/
/*! Construct an empty data element from a header.
- The data vectors will have space allocated, but they will be
filled with all zero bytes.
- If the header was "empty" (ended in "/>"), then no vectors will
be allocated, and nel->vec_num=0.
- This function is used by NI_read_element() to create the
data element after the header has been parsed.
- 27 Mar 2003: modified to allow vec_len=0, indicating vector
length to be inferred from amount of data
-------------------------------------------------------------------------*/
NI_element * make_empty_data_element( header_stuff *hs )
{
NI_element *nel ;
int ii ;
if( hs == NULL || hs->name == NULL ) return NULL ;
#ifdef NIML_DEBUG
NI_dpr("ENTER make_empty_data_element\n") ;
#endif
nel = NI_malloc(NI_element, sizeof(NI_element) ) ;
nel->type = NI_ELEMENT_TYPE ;
nel->outmode = -1 ; /* 29 Mar 2005 */
/* move name and attributes from hs to new element */
nel->name = hs->name ; hs->name = NULL ;
nel->attr_num = hs->nattr ;
if( nel->attr_num > 0 ){
nel->attr_lhs = hs->lhs ; hs->lhs = NULL ;
nel->attr_rhs = hs->rhs ; hs->rhs = NULL ;
} else {
nel->attr_lhs = nel->attr_rhs = NULL ;
}
/* set default vector parameters [indicating no data] */
nel->vec_num = 0 ;
nel->vec_len = 0 ;
nel->vec_typ = NULL ;
nel->vec = NULL ;
nel->vec_filled = 0 ; /* no data has been filled into vectors */
nel->vec_rank = 0 ;
nel->vec_axis_len = NULL ;
nel->vec_axis_delta = NULL ;
nel->vec_axis_origin = NULL ;
nel->vec_axis_unit = NULL ;
nel->vec_axis_label = NULL ;
if( !hs->empty ){ /* find and process ni_* attributes about vectors */
/* ni_type attribute: set types of vectors */
ii = string_index( "ni_type" , nel->attr_num , nel->attr_lhs ) ;
if( ii >= 0 && nel->attr_rhs[ii] != NULL ){
int_array *iar = decode_type_string( nel->attr_rhs[ii] ) ;
if( iar != NULL ){
nel->vec_num = iar->num ; /* number of vectors */
nel->vec_typ = iar->ar ; /* vector types */
NI_free(iar) ; /* just the shell of the struct */
}
}
/* ni_dimen attribute: set vector length and rank */
ii = string_index( "ni_dimen" , nel->attr_num , nel->attr_lhs ) ;
if( ii >= 0 && nel->attr_rhs[ii] != NULL ){
int_array *dar = decode_dimen_string( nel->attr_rhs[ii] ) ;
if( dar != NULL && dar->num > 0 ){
int nd=dar->num , qq,pp ;
/* compute product of all dimensions */
for( qq=1,pp=0 ; pp < nd ; pp++ ) qq *= dar->ar[pp] ;
nel->vec_len = qq ; /* length of vectors */
nel->vec_rank = nd ; /* number of dimensions */
nel->vec_axis_len = dar->ar ; /* array of dimension lengths */
NI_free(dar) ; /* just the struct shell */
if( nel->vec_len == 0 ) /* 27 Mar 2003 */
nel->vec_rank = 1 ;
}
}
/* if we had ni_dimen, also try ni_delta */
ii = string_index( "ni_delta" , nel->attr_num , nel->attr_lhs ) ;
if( ii >= 0 && nel->vec_rank > 0 ){
NI_str_array *sar = NI_decode_string_list( nel->attr_rhs[ii] , NULL ) ;
if( sar != NULL && sar->num > 0 ){
int ns=sar->num , nd=nel->vec_rank , pp ;
nel->vec_axis_delta = NI_malloc(float,sizeof(float)*nd) ;
if( nd > ns ) nd = ns ;
for( pp=0 ; pp < nd ; pp++ )
sscanf( sar->str[pp] , "%f" , nel->vec_axis_delta+pp ) ;
NI_delete_str_array(sar) ;
}
}
/* if we had ni_dimen, also try ni_origin */
ii = string_index( "ni_origin" , nel->attr_num , nel->attr_lhs ) ;
if( ii >= 0 && nel->vec_rank > 0 ){
NI_str_array *sar = NI_decode_string_list( nel->attr_rhs[ii] , NULL ) ;
if( sar != NULL && sar->num > 0 ){
int ns=sar->num , nd=nel->vec_rank , pp ;
nel->vec_axis_origin = NI_malloc(float,sizeof(float)*nd) ;
if( nd > ns ) nd = ns ;
for( pp=0 ; pp < nd ; pp++ )
sscanf( sar->str[pp] , "%f" , nel->vec_axis_origin+pp ) ;
NI_delete_str_array(sar) ;
}
}
/* if we had ni_dimen, also try ni_units */
ii = string_index( "ni_units" , nel->attr_num , nel->attr_lhs ) ;
if( ii >= 0 && nel->vec_rank > 0 ){
NI_str_array *sar = NI_decode_string_list( nel->attr_rhs[ii] , NULL ) ;
if( sar != NULL && sar->num > 0 ){
int ns=sar->num , nd=nel->vec_rank , pp ;
nel->vec_axis_unit = NI_malloc(char*,sizeof(char *)*nd) ;
if( nd > ns ) nd = ns ;
for( pp=0 ; pp < nd ; pp++ )
nel->vec_axis_unit[pp] = NI_strdup(sar->str[pp]) ;
NI_delete_str_array(sar) ;
}
}
/* if we had ni_dimen, also try ni_axes */
ii = string_index( "ni_axes" , nel->attr_num , nel->attr_lhs ) ;
if( ii >= 0 && nel->vec_rank > 0 ){
NI_str_array *sar = NI_decode_string_list( nel->attr_rhs[ii] , NULL ) ;
if( sar != NULL && sar->num > 0 ){
int ns=sar->num , nd=nel->vec_rank , pp ;
nel->vec_axis_label = NI_malloc(char*,sizeof(char *)*nd) ;
if( nd > ns ) nd = ns ;
for( pp=0 ; pp < nd ; pp++ )
nel->vec_axis_label[pp] = NI_strdup(sar->str[pp]) ;
NI_delete_str_array(sar) ;
}
}
/* supply vector parameters if none was given */
/* (remember, we DON'T have an empty element) */
if( nel->vec_num == 0 ){ /* default type */
nel->vec_num = 1 ;
nel->vec_typ = NI_malloc(int,sizeof(int)) ;
nel->vec_typ[0] = NI_BYTE ;
}
if( nel->vec_rank == 0 ){ /* default dimensions */
nel->vec_len = 0 ;
nel->vec_rank = 1 ;
nel->vec_axis_len = NI_malloc(int, sizeof(int)) ;
nel->vec_axis_len[0] = 1 ;
}
/* now allocate space for vectors defined above */
nel->vec = NI_malloc(void*, sizeof(void *)*nel->vec_num ) ;
/* 27 Mar 2003: only allocate space if we know how long they are */
if( nel->vec_len > 0 ){
for( ii=0 ; ii < nel->vec_num ; ii++ )
nel->vec[ii] = NI_malloc(void,
NI_type_size(nel->vec_typ[ii])*nel->vec_len) ;
} else {
for( ii=0 ; ii < nel->vec_num ; ii++ )
nel->vec[ii] = NULL ;
}
} /* end of processing non-empty header stuff */
return nel ;
}
/*-------------------------------------------------------------------------*/
/*! Make an empty group element from parsed header info.
The attributes in the header are assigned to the group, and the group
parts are initialized to nothing.
---------------------------------------------------------------------------*/
NI_group * make_empty_group_element( header_stuff *hs )
{
NI_group *ngr ;
if( hs == NULL || hs->name == NULL ) return NULL ;
ngr = NI_malloc(NI_group, sizeof(NI_group) ) ;
ngr->type = NI_GROUP_TYPE ;
ngr->name = hs->name ; hs->name = NULL ; /* 24 Feb 2005 */
ngr->outmode = -1 ; /* 29 Mar 2005 */
/* move attributes from hs to new element */
ngr->attr_num = hs->nattr ;
if( ngr->attr_num > 0 ){
ngr->attr_lhs = hs->lhs ; hs->lhs = NULL ;
ngr->attr_rhs = hs->rhs ; hs->rhs = NULL ;
} else {
ngr->attr_lhs = ngr->attr_rhs = NULL ;
}
/* have no pieces-parts yet */
ngr->part_num = 0 ;
ngr->part_typ = NULL ;
ngr->part = NULL ;
return ngr ;
}
/*-------------------------------------------------------------------------*/
/*! Byte size of a given integer type code.
Modified 13 Feb 2003 to use the new rowtype stuff.
---------------------------------------------------------------------------*/
int NI_type_size( int tval )
{
int ii = NI_rowtype_code_to_size( tval ) ;
return (ii > 0) ? ii : 0 ;
}
/*************************************************************************/
/********** Functions to create NIML data and group elements *************/
/*************************************************************************/
/*-----------------------------------------------------------------------*/
/*! Return the type of something that points to a NI element.
- The input should be point to a NI_element, NI_group, or NI_procins.
- The return value is NI_ELEMENT_TYPE, NI_GROUP_TYPE, NI_PROCINS_TYPE,
or -1 if the type is anything else or unknowable.
-------------------------------------------------------------------------*/
int NI_element_type( void *nini )
{
NI_element *nel = (NI_element *) nini ;
NI_group *ngr = (NI_group *) nini ;
NI_procins *npi = (NI_procins *) nini ; /* 16 Mar 2005 */
if( nini == NULL ) return -1 ;
if( nel->type == NI_ELEMENT_TYPE ) return NI_ELEMENT_TYPE ;
if( ngr->type == NI_GROUP_TYPE ) return NI_GROUP_TYPE ;
if( npi->type == NI_PROCINS_TYPE ) return NI_PROCINS_TYPE ;
return -1 ;
}
/*-----------------------------------------------------------------------*/
/*! Return the name of a NI element. If the input is bad, returns
a NULL pointer. Do not free this pointer! It points to the
name string inside the element struct.
-------------------------------------------------------------------------*/
char * NI_element_name( void *nini )
{
NI_element *nel = (NI_element *) nini ;
NI_group *ngr = (NI_group *) nini ;
NI_procins *npi = (NI_procins *) nini ;
if( nini == NULL ) return NULL ;
if( nel->type == NI_ELEMENT_TYPE ) return nel->name ;
if( ngr->type == NI_GROUP_TYPE ) return ngr->name ;
if( npi->type == NI_PROCINS_TYPE ) return npi->name ;
return NULL ;
}
/*-----------------------------------------------------------------------*/
/*! Expunge a data or group element and its contents from the universe.
-------------------------------------------------------------------------*/
void NI_free_element( void *nini )
{
int ii , tt=NI_element_type(nini) ;
if( tt < 0 ) return ; /* bad input */
/*-- erase contents of data element --*/
if( tt == NI_ELEMENT_TYPE ){
NI_element *nel = (NI_element *)nini ;
NI_free(nel->name) ;
for( ii=0 ; ii < nel->attr_num ; ii++ ){
NI_free( nel->attr_lhs[ii] ) ;
NI_free( nel->attr_rhs[ii] ) ;
}
NI_free( nel->attr_lhs ) ;
NI_free( nel->attr_rhs ) ;
/* 14 Feb 2003: NI_free_column() will also free var dim arrays */
if( nel->vec != NULL )
for( ii=0 ; ii < nel->vec_num ; ii++ )
NI_free_column( NI_rowtype_find_code(nel->vec_typ[ii]) ,
nel->vec_len , nel->vec[ii] ) ;
NI_free( nel->vec_typ ) ;
NI_free( nel->vec ) ;
NI_free(nel->vec_axis_len) ;
NI_free(nel->vec_axis_delta) ;
NI_free(nel->vec_axis_origin) ;
NI_free(nel->vec_axis_unit) ;
NI_free(nel->vec_axis_label) ;
NI_free( nel ) ;
/*-- erase contents of group element --*/
} else if( tt == NI_GROUP_TYPE ){
NI_group *ngr = (NI_group *)nini ;
for( ii=0 ; ii < ngr->attr_num ; ii++ ){
NI_free( ngr->attr_lhs[ii] ) ;
NI_free( ngr->attr_rhs[ii] ) ;
}
NI_free( ngr->attr_lhs ) ;
NI_free( ngr->attr_rhs ) ;
if( ngr->part != NULL ){
for( ii=0 ; ii < ngr->part_num ; ii++ )
NI_free_element( ngr->part[ii] ) ; /* recursion */
}
NI_free( ngr->part_typ ) ;
NI_free( ngr->part ) ;
NI_free( ngr->name ) ; /* 03 Jun 2002 */
NI_free( ngr ) ;
/*-- erase contents of processing instruction --*/
} else if( tt == NI_PROCINS_TYPE ){
NI_procins *npi = (NI_procins *)nini ;
for( ii=0 ; ii < npi->attr_num ; ii++ ){
NI_free( npi->attr_lhs[ii] ) ;
NI_free( npi->attr_rhs[ii] ) ;
}
NI_free( npi->attr_lhs ) ;
NI_free( npi->attr_rhs ) ;
NI_free( npi->name ) ; /* 03 Jun 2002 */
NI_free( npi ) ;
}
return ;
}
/*-----------------------------------------------------------------------*/
/*! Expunge all data from element or group. 17 Jul 2006 [rickr]
-------------------------------------------------------------------------*/
void NI_free_element_data( void *nini )
{
int ii , tt=NI_element_type(nini) ;
if( tt < 0 ) return ; /* bad input */
/*-- if element, nuke data --*/
if( tt == NI_ELEMENT_TYPE ){
NI_element *nel = (NI_element *)nini ;
if( nel->vec != NULL ){
for( ii=0 ; ii < nel->vec_num ; ii++ )
NI_free_column( NI_rowtype_find_code(nel->vec_typ[ii]) ,
nel->vec_len , nel->vec[ii] ) ;
NI_free( nel->vec ) ;
nel->vec = NULL ;
}
/*-- if group, recur --*/
} else if( tt == NI_GROUP_TYPE ){
NI_group *ngr = (NI_group *)nini ;
if( ngr->part != NULL ){
for( ii=0 ; ii < ngr->part_num ; ii++ )
NI_free_element_data( ngr->part[ii] ) ; /* recursion */
}
}
/*-- no other cases for data --*/
return ;
}
/*-----------------------------------------------------------------------*/
/*! Create a new data element.
- name = string name for header.
- veclen = size (length) of vectors (ni_dimen attribute).
- Vectors are added with NI_add_column().
- Set this to zero for "empty" elements (those with only
headers, no data).
Return is NULL if inputs are stupid or criminal or insane.
-------------------------------------------------------------------------*/
NI_element * NI_new_data_element( char *name , int veclen )
{
NI_element *nel ;
if( name == NULL || name[0] == '\0' || veclen < 0 ) return NULL ;
nel = NI_malloc(NI_element, sizeof(NI_element) ) ;
nel->type = NI_ELEMENT_TYPE ; /* mark as being a data element */
nel->outmode = -1 ; /* 29 Mar 2005 */
nel->name = NI_strdup(name) ;
nel->attr_num = 0 ;
nel->attr_lhs = nel->attr_rhs = NULL ; /* no attributes yes */
nel->vec_num = 0 ; /* no vectors yet */
nel->vec_typ = NULL ;
nel->vec = NULL ;
if( veclen == 0 ){ /* empty element */
nel->vec_len = 0 ;
nel->vec_filled = 0 ;
nel->vec_rank = 0 ;
nel->vec_axis_len = NULL ;
} else { /* element with data to */
nel->vec_len = veclen ; /* come via NI_add_column */
nel->vec_filled = veclen ;
nel->vec_rank = 1 ;
nel->vec_axis_len = NI_malloc(int, sizeof(int)) ;
nel->vec_axis_len[0] = veclen ;
}
nel->vec_axis_delta = NULL ;
nel->vec_axis_origin = NULL ;
nel->vec_axis_unit = NULL ;
nel->vec_axis_label = NULL ;
return nel ;
}
/*-----------------------------------------------------------------------*/
/*! Add a vector (column) of data to a data element.
- nel = data element to modify
- typ = integer type code of data (e.g., NI_FLOAT)
- arr = pointer to data values - must be an array of length veclen
(same value as used in NI_new_data_element() call)
- if arr is NULL, then will add a zero-filled column of the given
type to the data element
The data array is copied into the element. If the element was
specified with veclen=0, then this function will do nothing.
Since this function has no return value, the only way to check for
such an error is to see if nel->vec_num was incremented. Or don't
be so stupid as to make this error.
-------------------------------------------------------------------------*/
void NI_add_column( NI_element *nel , int typ , void *arr )
{
int nn ;
NI_rowtype *rt ;
/* check for reasonable inputs */
if( nel == NULL || nel->vec_len <= 0 ) return ;
if( nel->type != NI_ELEMENT_TYPE ) return ;
rt = NI_rowtype_find_code(typ) ; if( rt == NULL ) return ;
/* get number of vectors currently in element */
nn = nel->vec_num ;
/* add 1 to the vec_typ array */
nel->vec_typ = NI_realloc( nel->vec_typ, int, sizeof(int)*(nn+1) ) ;
nel->vec_typ[nn] = typ ;
/* add 1 element to the vec array, and copy data into it */
nel->vec = NI_realloc( nel->vec , void*, sizeof(void *)*(nn+1) ) ;
if( arr != NULL )
nel->vec[nn] = NI_copy_column( rt , nel->vec_len , arr ) ;
else
nel->vec[nn] = NI_malloc(void, rt->size * nel->vec_len ) ;
/* add 1 to the count of vectors */
nel->vec_num = nn+1 ;
/* if element has "ni_type" attribute, adjust it 14 Jul 2006 [rickr] */
if( NI_get_attribute(nel, "ni_type") )
NI_set_ni_type_atr(nel) ;
return ;
}
/*!
Like add_column, but inserts the column at nel->vec[icol] rather than
at the end.
if icol < 0 || icol > nel->vec_num then icol = nel->vec_num
*/
void NI_insert_column( NI_element *nel , int typ , void *arr, int icol )
{
int nn, ii ;
NI_rowtype *rt ;
/* check for reasonable inputs */
if( nel == NULL || nel->vec_len <= 0 ) return ;
if( nel->type != NI_ELEMENT_TYPE ) return ;
rt = NI_rowtype_find_code(typ) ; if( rt == NULL ) return ;
/* get number of vectors currently in element */
nn = nel->vec_num ;
if (icol > nn || icol < 0) icol = nn;
/* call add column */
NI_add_column(nel, typ, arr);
/* check on success */
if (nel->vec_num != nn+1) return ; /* misere */
nn = nel->vec_num ; /* the new number of vectors */
NI_move_column(nel, nn-1, icol);
return ;
}
/*!
move a column from index ibefore to iafter
if ibefore (or iafter) is (< 0 || > nel->vec_num) then
ibefore = nel->vec_num-1
*/
void NI_move_column(NI_element *nel, int ibefore, int iafter)
{
int nn, ii ;
int typ_buf;
void *col_buf;
if (nel == NULL || nel->vec_len <= 0 ) return ;
nn = nel->vec_num ;
if (ibefore < 0 || ibefore >= nn) ibefore = nn-1;
if (iafter < 0 || iafter >= nn) iafter = nn-1;
/* nothing to see here? */
if (ibefore == iafter) return;
/* do the deed */
/* store the initial values */
typ_buf = nel->vec_typ[ibefore];
col_buf = nel->vec[ibefore];
/* shift */
if (ibefore > iafter) {
/* shift columns to left*/
for (ii=ibefore; ii > iafter; --ii) {
nel->vec[ii] = nel->vec[ii-1];
nel->vec_typ[ii] = nel->vec_typ[ii-1];
}
} else {
/* shift columns to right*/
for (ii=ibefore; ii < iafter; ++ii) {
nel->vec[ii] = nel->vec[ii+1];
nel->vec_typ[ii] = nel->vec_typ[ii+1];
}
}
/* insert the trouble maker back*/
nel->vec[iafter] = col_buf;
nel->vec_typ[iafter] = typ_buf;
/* house keeping */
/* if element has "ni_type" attribute, adjust it 14 Jul 2006 [rickr] */
if( NI_get_attribute(nel, "ni_type") )
NI_set_ni_type_atr(nel) ;
return ;
}
/*!
Do we really need to document this too?
Removes column irm from nel. If irm < 0 or
irm >= nel->vec_num irm = nel->vec_num -1
*/
void NI_remove_column(NI_element *nel, int irm)
{
int nn;
if (nel == NULL || nel->vec_len <= 0 ) return ;
nn = nel->vec_num ;
if (irm < 0 || irm >= nn) irm = nn-1;
/* move irm to last column */
NI_move_column(nel, irm, -1);
/* free the last column */
NI_free_column( NI_rowtype_find_code(nel->vec_typ[nn-1]) ,
nel->vec_len , nel->vec[nn-1] ) ;
nel->vec[nn-1] = NULL; /* to be sure */
/* decrease the number of columns */
--nn;
nel->vec_num = nn;
/* get rid of extra space */
nel->vec_typ = NI_realloc( nel->vec_typ, int, sizeof(int)*(nn-1) ) ;
nel->vec = NI_realloc( nel->vec , void*, sizeof(void *)*(nn-1) ) ;
/* if element has "ni_type" attribute, adjust it 14 Jul 2006 [rickr] */
if( NI_get_attribute(nel, "ni_type") )
NI_set_ni_type_atr(nel) ;
return;
}
/*------------------------------------------------------------------------*/
/*! Change the length of all the columns in a data element.
- If the columns are longer, they will be zero filled.
- New values can be inserted later with NI_insert_value().
- If the columns are shorter, data will be lost.
- You cannot use this to convert an element to/from being empty;
that is, newlen > 0 is required, as is nel->vec_len on input.
--------------------------------------------------------------------------*/
void NI_alter_veclen( NI_element *nel , int newlen )
{
int oldlen , ii ;
NI_rowtype *rt ;
char *pt ;
if( nel == NULL || nel->type != NI_ELEMENT_TYPE ) return ;
if( nel->vec_len <= 0 || newlen <= 0 ) return ;
if( nel->vec_num == 0 ){ /* if have no data yet */
nel->vec_len = nel->vec_filled = newlen; return;
}
oldlen = nel->vec_len ; if( oldlen == newlen ) return ;
for( ii=0 ; ii < nel->vec_num ; ii++ ){
rt = NI_rowtype_find_code( nel->vec_typ[ii] ) ;
nel->vec[ii] = NI_realloc( nel->vec[ii] , void , rt->size * newlen ) ;
if( oldlen < newlen ){
pt = ((char *)nel->vec[ii]) + (rt->size * oldlen) ; /* zero fill */
memset( pt , 0 , (newlen-oldlen)*rt->size ) ; /* new data! */
}
}
nel->vec_len = nel->vec_filled = newlen ; return ;
}
/*------------------------------------------------------------------------*/
/*! As in NI_add_column(), but adding every stride-th element from arr.
Thus, arr should be at least nel->vec_len * stride elements long.
--------------------------------------------------------------------------*/
void NI_add_column_stride( NI_element *nel, int typ, void *arr, int stride )
{
int nn , ii ;
NI_rowtype *rt ;
char *idat ;
/* check for reasonable inputs */
if( nel == NULL || nel->vec_len <= 0 ) return ;
if( nel->type != NI_ELEMENT_TYPE ) return ;
rt = NI_rowtype_find_code(typ) ; if( rt == NULL ) return ;
/* add an empty column */
NI_add_column( nel , typ , NULL ) ;
if( arr == NULL ) return ; /* no input data ==> we're done */
/* loop over inputs and put them in one at a time */
nn = nel->vec_num-1 ;
idat = (char *) arr ;
for( ii=0 ; ii < nel->vec_len ; ii++ )
NI_insert_value( nel , ii , nn , idat + (ii*stride*rt->size) ) ;
return ;
}
/*!
See NI_insert_column for inspiration
*/
void NI_insert_column_stride( NI_element *nel, int typ, void *arr, int stride, int icol )
{
int nn , ii ;
NI_rowtype *rt ;
char *idat ;
/* check for reasonable inputs */
if( nel == NULL || nel->vec_len <= 0 ) return ;
if( nel->type != NI_ELEMENT_TYPE ) return ;
rt = NI_rowtype_find_code(typ) ; if( rt == NULL ) return ;
/* get number of vectors currently in element */
nn = nel->vec_num ;
if (icol > nn || icol < 0) icol = nn;
/* call add column_stride */
NI_add_column_stride(nel, typ, arr, stride);
/* check on success */
if (nel->vec_num != nn+1) return ; /* misere */
nn = nel->vec_num ; /* the new number of vectors */
NI_move_column(nel, nn-1, icol);
return ;
}
/*------------------------------------------------------------------------*/
/*! ZSS; Fills an already created column with values up to vec_filled
the values in arr are inserted into nel->vec[nn]
--------------------------------------------------------------------------*/
void NI_fill_column_stride( NI_element *nel, int typ,
void *arr, int nn, int stride )
{
int ii , nf;
NI_rowtype *rt ;
char *idat ;
/* check for reasonable inputs */
if( nel == NULL || nel->vec_len <= 0 ) return ;
if( nel->type != NI_ELEMENT_TYPE ) return ;
rt = NI_rowtype_find_code(typ) ; if( rt == NULL ) return ;
/* check for NULL column or other similar errors*/
if( arr == NULL ) return ;
if( nel->vec[nn] == NULL ) return ;
if( nn < 0 || nn >= nel->vec_num ) return ;
if( typ != nel->vec_typ[nn] ) return ;
/* loop over inputs and put them in */
if( nel->vec_filled > 0 && nel->vec_filled <= nel->vec_len )
nf = nel->vec_filled ;
else
nf = nel->vec_len ;
idat = (char *) arr ;
for( ii=0 ; ii < nf ; ii++ )
NI_insert_value( nel , ii , nn , idat + (ii*stride*rt->size) ) ;
return ;
}
/*------------------------------------------------------------------------*/
/*! Replace the row-th value in the col-th column of the data element.
- dat is the pointer to the data values to copy into the element.
- The column must have been created with NI_add_column() before
calling this function!
- NOTE WELL: When the column type is NI_STRING, it is a mistake
to call this function with dat being a pointer to the C string
to insert. Instead, dat should be a pointer to the pointer to
the C string. For example:
- char *me = "RWCox" ;
- WRONG: NI_insert_value ( nel, 3,5, me ) ; [Seg Fault ensues]
- RIGHT: NI_insert_value ( nel, 3,5, &me ) ;
- RIGHT: NI_insert_string( nel, 3,5, me ) ;
- The last case illustrates the NI_insert_string() function,
which can be used to simplify insertion into a column
of Strings; that function is just a simple wrapper to call
NI_insert_value() properly.
- The reason the first example is WRONG is that dat is supposed
to point to the data to be stored. In the case of a String,
the data is the pointer to the C string.
--------------------------------------------------------------------------*/
void NI_insert_value( NI_element *nel, int row, int col, void *dat )
{
NI_rowtype *rt ;
char *cdat , *idat=(char *)dat , *qpt ;
int jj , kk ;
/* check for reasonable inputs */
if( nel == NULL || idat == NULL ) return ;
if( nel->type != NI_ELEMENT_TYPE ) return ;
if( nel->vec_len <= 0 ) return ;
if( row < 0 || row >= nel->vec_len ) return ;
if( col < 0 || col >= nel->vec_num ) return ;
rt = NI_rowtype_find_code( nel->vec_typ[col] ) ;
if( rt == NULL ) return ;
cdat = (char *) nel->vec[col] ; /* points to column data */
cdat = cdat + rt->size * row ; /* points to data to alter */
/* shallow copy of input data over data now present */
memcpy( cdat , idat , rt->size ) ;
/* copy any var dim arrays inside */
if( ROWTYPE_is_varsize(rt) ){
for( jj=0 ; jj < rt->part_num ; jj++ ){ /* loop over parts */
if( rt->part_typ[jj] == NI_STRING ){ /* a string part */
char **apt = (char **)(cdat+rt->part_off[jj]) ; /* *apt => data */
qpt = NI_strdup(*apt) ; *apt = qpt ;
} else if( rt->part_dim[jj] >= 0 ){ /* var dim array */
char **apt = (char **)(cdat+rt->part_off[jj]) ; /* *apt => data */
if( *apt != NULL ){
kk = ROWTYPE_part_dimen(rt,cdat,jj) * rt->part_rtp[jj]->size ;
qpt = NI_malloc(char, kk) ; memcpy(qpt,*apt,kk) ; *apt = qpt ;
}
}
}
}
return ;
}
/*------------------------------------------------------------------------*/
void NI_insert_string( NI_element *nel, int row, int col, char *str )
{
if( nel == NULL || str == NULL ) return ;
if( nel->type != NI_ELEMENT_TYPE ) return ;
if( row < 0 || row >= nel->vec_len ) return ;
if( col < 0 || col >= nel->vec_num ) return ;
if( nel->vec_typ[col] != NI_STRING ) return ;
NI_insert_value( nel , row,col , &str ); return ;
}
/*------------------------------------------------------------------------*/
/*! Add an attribute to a data or group element.
If an attribute with the same attname already exists, then
it will be replaced with this one.
--------------------------------------------------------------------------*/
void NI_set_attribute( void *nini , char *attname , char *attvalue )
{
int nn , tt=NI_element_type(nini) ;
if( tt < 0 || attname == NULL || attname[0] == '\0' ) return ;
/* input is a data element */
if( tt == NI_ELEMENT_TYPE ){
NI_element *nel = (NI_element *) nini ;
/* see if name is already in element header */
for( nn=0 ; nn < nel->attr_num ; nn++ )
if( strcmp(nel->attr_lhs[nn],attname) == 0 ) break ;
/* if not, then add a header attribute */
if( nn == nel->attr_num ){
nel->attr_lhs = NI_realloc( nel->attr_lhs, char*, sizeof(char *)*(nn+1) );
nel->attr_rhs = NI_realloc( nel->attr_rhs, char*, sizeof(char *)*(nn+1) );
nel->attr_num = nn+1 ;
} else {
NI_free(nel->attr_lhs[nn]) ; /* free old attribute */
NI_free(nel->attr_rhs[nn]) ;
}
nel->attr_lhs[nn] = NI_strdup(attname) ;
nel->attr_rhs[nn] = NI_strdup(attvalue);
/* input is a group element */
} else if( tt == NI_GROUP_TYPE ){
NI_group *ngr = (NI_group *) nini ;
for( nn=0 ; nn < ngr->attr_num ; nn++ )
if( strcmp(ngr->attr_lhs[nn],attname) == 0 ) break ;
if( nn == ngr->attr_num ){
ngr->attr_lhs = NI_realloc( ngr->attr_lhs, char*, sizeof(char *)*(nn+1) );
ngr->attr_rhs = NI_realloc( ngr->attr_rhs, char*, sizeof(char *)*(nn+1) );
ngr->attr_num = nn+1 ;
} else {
NI_free(ngr->attr_lhs[nn]) ;
NI_free(ngr->attr_rhs[nn]) ;
}
ngr->attr_lhs[nn] = NI_strdup(attname) ;
ngr->attr_rhs[nn] = NI_strdup(attvalue);
/* input is a processing instruction */
} else if( tt == NI_PROCINS_TYPE ){
NI_procins *npi = (NI_procins *) nini ;
for( nn=0 ; nn < npi->attr_num ; nn++ )
if( strcmp(npi->attr_lhs[nn],attname) == 0 ) break ;
if( nn == npi->attr_num ){
npi->attr_lhs = NI_realloc( npi->attr_lhs, char*, sizeof(char *)*(nn+1) );
npi->attr_rhs = NI_realloc( npi->attr_rhs, char*, sizeof(char *)*(nn+1) );
npi->attr_num = nn+1 ;
} else {
NI_free(npi->attr_lhs[nn]) ;
NI_free(npi->attr_rhs[nn]) ;
}
npi->attr_lhs[nn] = NI_strdup(attname) ;
npi->attr_rhs[nn] = NI_strdup(attvalue);
}
return ;
}
/*-----------------------------------------------------------------------*/
/*! Get an attribute with the given LHS name. Returns a pointer to the
RHS field in the element if the attribute name is found; otherwise
returns NULL. If the LHS is found, but the RHS is NULL, returns
a pointer to an empty C string ("\0"). Do not free() the result
from this function, since it points to the internal field
of the element!
-------------------------------------------------------------------------*/
char * NI_get_attribute( void *nini , char *attname )
{
int nn , tt=NI_element_type(nini) ;
static char *zorkon = "\0" ;
if( tt < 0 || attname == NULL || attname[0] == '\0' ) return NULL ;
/* input is a data element */
if( tt == NI_ELEMENT_TYPE ){
NI_element *nel = (NI_element *) nini ;
for( nn=0 ; nn < nel->attr_num ; nn++ )
if( strcmp(nel->attr_lhs[nn],attname) == 0 ) break ;
if( nn == nel->attr_num ) return NULL ;
if( nel->attr_rhs[nn] == NULL ) return zorkon ;
return nel->attr_rhs[nn] ;
/* input is a group element */
} else if( tt == NI_GROUP_TYPE ){
NI_group *ngr = (NI_group *) nini ;
for( nn=0 ; nn < ngr->attr_num ; nn++ )
if( strcmp(ngr->attr_lhs[nn],attname) == 0 ) break ;
if( nn == ngr->attr_num ) return NULL ;
if( ngr->attr_rhs[nn] == NULL ) return zorkon ;
return ngr->attr_rhs[nn] ;
/* input is a processing instruction */
} else if( tt == NI_PROCINS_TYPE ){
NI_procins *npi = (NI_procins *) nini ;
for( nn=0 ; nn < npi->attr_num ; nn++ )
if( strcmp(npi->attr_lhs[nn],attname) == 0 ) break ;
if( nn == npi->attr_num ) return NULL ;
if( npi->attr_rhs[nn] == NULL ) return zorkon ;
return npi->attr_rhs[nn] ;
}
return NULL ; /* should never be reached */
}
/*-----------------------------------------------------------------------*/
/*! Set the dimen attribute for a data element.
-------------------------------------------------------------------------*/
void NI_set_dimen( NI_element *nel , int rank , int *nd )
{
int ii , ntot ;
if( nel == NULL || nel->type != NI_ELEMENT_TYPE ||
rank < 1 || nd == NULL ) return ; /* bad */
for( ntot=1,ii=0 ; ii < rank ; ii++ ){
if( nd[ii] <= 0 ) return ; /* bad */
ntot *= nd[ii] ;
}
if( ntot != nel->vec_len ) return ; /* bad */
nel->vec_rank = rank ;
nel->vec_axis_len = NI_realloc( nel->vec_axis_len, int, sizeof(int)*rank ) ;
memcpy( nel->vec_axis_len , nd , sizeof(int)*rank ) ;
return ;
}
/*-----------------------------------------------------------------------*/
/*! Set the delta attribute for a data element.
Do not call this function until NI_set_dimen() has been called,
unless there is only 1 dimension (which is the default).
-------------------------------------------------------------------------*/
void NI_set_delta( NI_element *nel , float *del )
{
if( nel == NULL || nel->type != NI_ELEMENT_TYPE ||
nel->vec_rank < 1 || del == NULL ) return ;
nel->vec_axis_delta = NI_realloc( nel->vec_axis_delta , float,
nel->vec_rank * sizeof(float) ) ;
memcpy( nel->vec_axis_delta , del , nel->vec_rank * sizeof(float) ) ;
return ;
}
/*-----------------------------------------------------------------------*/
/*! Set the origin attribute for a data element.
Do not call this function until NI_set_dimen() has been called,
unless there is only 1 dimension (which is the default).
-------------------------------------------------------------------------*/
void NI_set_origin( NI_element *nel , float *org )
{
if( nel == NULL || nel->type != NI_ELEMENT_TYPE ||
nel->vec_rank < 1 || org == NULL ) return ;
nel->vec_axis_origin = NI_realloc( nel->vec_axis_origin , float,
nel->vec_rank * sizeof(float) ) ;
memcpy( nel->vec_axis_origin , org , nel->vec_rank * sizeof(float) ) ;
return ;
}
/*-----------------------------------------------------------------------*/
/*! Set the units attribute for a data element.
Do not call this function until NI_set_dimen() has been called,
unless there is only 1 dimension (which is the default).
-------------------------------------------------------------------------*/
void NI_set_units( NI_element *nel , char **units )
{
int ii ;
if( nel == NULL || nel->type != NI_ELEMENT_TYPE ||
nel->vec_rank < 1 || units == NULL ) return ;
nel->vec_axis_unit = NI_realloc( nel->vec_axis_unit , char*,
nel->vec_rank * sizeof(char *) ) ;
for( ii=0 ; ii < nel->vec_rank ; ii++ )
nel->vec_axis_unit[ii] = NI_strdup( units[ii] ) ;
return ;
}
/*-----------------------------------------------------------------------*/
/*! Set the axes attribute for a data element.
Do not call this function until NI_set_dimen() has been called,
unless there is only 1 dimension (which is the default).
-------------------------------------------------------------------------*/
void NI_set_axes( NI_element *nel , char **ax )
{
int ii ;
if( nel == NULL || nel->type != NI_ELEMENT_TYPE ||
nel->vec_rank < 1 || ax == NULL ) return ;
nel->vec_axis_label = NI_realloc( nel->vec_axis_label , char*,
nel->vec_rank * sizeof(char *) ) ;
for( ii=0 ; ii < nel->vec_rank ; ii++ )
nel->vec_axis_label[ii] = NI_strdup( ax[ii] ) ;
return ;
}
/*-----------------------------------------------------------------------*/
/*! Create a new processing instruction with a given 'target' name.
-------------------------------------------------------------------------*/
NI_procins * NI_new_processing_instruction( char *name )
{
NI_procins *npi ;
if( name == NULL || name[0] == '\0' ) return NULL ;
npi = NI_malloc(NI_procins,sizeof(NI_procins)) ;
npi->type = NI_PROCINS_TYPE ;
npi->name = NI_strdup(name) ;
npi->attr_num = 0 ;
npi->attr_lhs = npi->attr_rhs = NULL ;
return npi ;
}
/*-----------------------------------------------------------------------*/
/*! Create a new group element.
-------------------------------------------------------------------------*/
NI_group * NI_new_group_element(void)
{
NI_group *ngr ;
ngr = NI_malloc(NI_group, sizeof(NI_group) ) ;
ngr->type = NI_GROUP_TYPE ;
ngr->outmode = -1 ; /* 29 Mar 2005 */
ngr->attr_num = 0 ;
ngr->attr_lhs = ngr->attr_rhs = NULL ;
ngr->part_num = 0 ;
ngr->part_typ = NULL ;
ngr->part = NULL ;
ngr->name = NULL ; /* 03 Jun 2002 */
return ngr ;
}
/*-----------------------------------------------------------------------*/
/*! Add an element to a group element.
-------------------------------------------------------------------------*/
void NI_add_to_group( NI_group *ngr , void *nini )
{
int nn , tt=NI_element_type(nini) ;
if( ngr == NULL || ngr->type != NI_GROUP_TYPE || tt < 0 ) return ;
nn = ngr->part_num ;
ngr->part_typ = NI_realloc( ngr->part_typ , int, sizeof(int)*(nn+1) ) ;
ngr->part_typ[nn] = tt ;
ngr->part = NI_realloc( ngr->part , void*, sizeof(void *)*(nn+1) );
ngr->part[nn] = nini ;
ngr->part_num = nn+1 ;
return ;
}
/*-----------------------------------------------------------------------*/
/*! Remove an element from a group. Does NOT delete the element;
that is the caller's responsibility, if desired.
-------------------------------------------------------------------------*/
void NI_remove_from_group( NI_group *ngr , void *nini ) /* 16 Apr 2005 */
{
int ii , nn , jj ;
if( ngr == NULL || ngr->type != NI_GROUP_TYPE || nini == NULL ) return ;
nn = ngr->part_num ;
for( ii=0 ; ii < nn ; ii++ ) /* search for part */
if( nini == ngr->part[ii] ) break ;
if( ii == nn ) return ; /* not found */
for( jj=ii+1 ; jj < nn ; jj++ ){ /* move parts above down */
ngr->part_typ[jj-1] = ngr->part_typ[jj] ;
ngr->part [jj-1] = ngr->part [jj] ;
}
ngr->part[nn-1] = NULL ; /* NULL-ify last part to be safe */
ngr->part_num -- ; /* reduce part count */
return ;
}
/*-----------------------------------------------------------------------*/
/*! Rename a group element from the default - 03 Jun 2002.
-------------------------------------------------------------------------*/
void NI_rename_group( NI_group *ngr , char *nam )
{
if( ngr == NULL || ngr->type != NI_GROUP_TYPE ) return ;
NI_free( ngr->name ) ;
ngr->name = NI_strdup(nam) ;
return ;
}
/*-----------------------------------------------------------------------*/
/*! Return a list of all elements in a group that have a given name.
- This is a 'shallow' search: if the group itself contains
groups, these sub-groups are not searched.
- Return value of function is number of elements found (might be 0).
- If something is found, then *nipt is an array of 'void *', each
of which points to a matching element.
- The returned elements might be group or data elements.
- Sample usage:
- int n,i ; void **nelar ;
- n = NI_search_group_shallow( ngr , "fred" , &nelar ) ;
- for( i=0 ; i < n ; i++ ) do_something( nelar[ii] ) ;
- if( n > 0 ) NI_free(nelar) ;
-------------------------------------------------------------------------*/
int NI_search_group_shallow( NI_group *ngr , char *enam , void ***nipt )
{
void **nelar=NULL , *nini ;
int ii , nn=0 ;
char *nm ;
if( ngr == NULL || ngr->type != NI_GROUP_TYPE ) return 0 ;
if( enam == NULL || *enam == '\0' || nipt == NULL ) return 0 ;
if( ngr->part_num == 0 ) return 0 ;
for( ii=0 ; ii < ngr->part_num ; ii++ ){
nini = ngr->part[ii] ;
nm = NI_element_name( nini ) ;
if( nm != NULL && strcmp(nm,enam) == 0 ){
/* added *size 11 Jul 2006 [rickr] */
nelar = (void **) NI_realloc(nelar,void*,(nn+1)*sizeof(void *)) ;
nelar[nn++] = nini ;
}
}
if( nn > 0 ) *nipt = nelar ;
return nn ;
}
/*-----------------------------------------------------------------------*/
/*! Return a list of all elements in a group that have a given name.
- This is a 'deep' search: if the group itself contains
groups, these sub-groups are searched, etc.
- If a group element has the name 'enam' AND a data element within
that group has the name 'enam' as well, they will BOTH be returned
in this list.
- Return value of function is number of elements found (might be 0).
- If something is found, then *nipt is an array of 'void *', each
of which points to a matching element.
- The returned elements might be group or data elements.
- Sample usage:
- int n,i ; void **nelar ;
- n = NI_search_group_shallow( ngr , "fred" , &nelar ) ;
- for( i=0 ; i < n ; i++ ) do_something( nelar[ii] ) ;
- if( n > 0 ) NI_free(nelar) ;
-------------------------------------------------------------------------*/
int NI_search_group_deep( NI_group *ngr , char *enam , void ***nipt )
{
void **nelar=NULL , *nini ;
int ii , nn=0 ;
char *nm ;
if( ngr == NULL || ngr->type != NI_GROUP_TYPE ) return 0 ;
if( enam == NULL || *enam == '\0' || nipt == NULL ) return 0 ;
if( ngr->part_num == 0 ) return 0 ;
for( ii=0 ; ii < ngr->part_num ; ii++ ){
nini = ngr->part[ii] ;
nm = NI_element_name( nini ) ;
if( nm != NULL && strcmp(nm,enam) == 0 ){
nelar = (void **) NI_realloc(nelar,void*,(nn+1)*sizeof(void *)) ;
nelar[nn++] = nini ;
}
if( NI_element_type(nini) == NI_GROUP_TYPE ){ /* recursion */
int nsub , jj ; void **esub ;
nsub = NI_search_group_deep( nini , enam , &esub ) ;
if( nsub > 0 ){
nelar = (void **) NI_realloc(nelar,void*,(nn+nsub)*sizeof(void *)) ;
for( jj=0 ; jj < nsub ; jj++ ) nelar[nn++] = esub[jj] ;
NI_free(esub) ;
}
}
}
if( nn > 0 ) *nipt = nelar ;
return nn ;
}
/*-----------------------------------------------------------------------*/
/*! add a ni_type attribute to the element 14 Jul 2006 [rickr]
(based on NI_write_element())
-------------------------------------------------------------------------*/
void NI_set_ni_type_atr( NI_element * nel )
{
char * buf ; /* alloc in blocks of ~1K (bob noted names up to 255 chars) */
char * posn ;
int ii, prev, count=0 ;
int req_len, total_len=1024 ;
if( ! nel || nel->vec_num <= 0 ) return ;
/* make enough space for a list of buffers, and init. to empty */
/* -- NI_rowtype_define uses 255 as a max rowtype name length */
buf = (char *)NI_malloc(char, total_len * sizeof(char)) ;
buf[0] = '\0' ;
for( prev=-1, ii=0; ii < nel->vec_num; ii++ ){
if( nel->vec_typ[ii] != prev ){ /* not the previous type */
if( prev >= 0 ){ /* apply previous type now */
posn = buf + strlen(buf);
if( count > 1 ) sprintf(posn, "%d*%s,", count, NI_type_name(prev));
else sprintf(posn, "%s,", NI_type_name(prev));
}
prev = nel->vec_typ[ii] ; /* save new type code */
count = 1 ; /* have 1 such type */
/* make sure there is enough space for the new code */
/* (old, new, and space for "5280*") 17 Jul 2006 [rickr] */
req_len = strlen(buf) + strlen(NI_type_name(prev)) + 10 ;
if( total_len < req_len )
buf = (char *)NI_realloc(buf, char, (req_len+1024) * sizeof(char)) ;
} else { /* same as previous type */
count++ ; /* so increment its count */
}
}
/* now write the last type found */
posn = buf + strlen(buf) ;
if( count > 1 ) sprintf(posn, "%d*%s", count, NI_type_name(prev));
else sprintf(posn, "%s", NI_type_name(prev));
/* now add the string as an attribute, and nuke the old string */
NI_set_attribute(nel, "ni_type", buf) ;
NI_free(buf) ;
return ;
}
syntax highlighted by Code2HTML, v. 0.9.1