1 #include "niml_private.h"
2
3 /*-----------------------------------------------------------------------*/
4 /* Vector labels [12 Sep 2018] */
5
NI_set_veclab_from_stringlist(NI_element * nel,char * vstr)6 void NI_set_veclab_from_stringlist( NI_element *nel , char *vstr )
7 {
8 if( NI_element_type(nel) != NI_ELEMENT_TYPE || vstr == NULL ) return ;
9
10 if( nel->vec_num > 0 ){
11 int pp ;
12 NI_str_array *sar = NI_decode_string_list( vstr , "," ) ;
13 if( sar != NULL && sar->num > 0 ){
14 int ns=sar->num ;
15 if( nel->vec_lab != NULL ) NI_free(nel->vec_lab) ;
16 nel->vec_lab = (char **)NI_malloc(char*,sizeof(char *)*nel->vec_num) ;
17 for( pp=0 ; pp < nel->vec_num ; pp++ ){
18 nel->vec_lab[pp] = (pp < ns) ? NI_strdup(sar->str[pp])
19 : NI_strdup("\0") ;
20 }
21 }
22 }
23 return ;
24 }
25
26 /*-----------------------------------------------------------------------*/
27
NI_set_attribute_from_veclab_array(NI_element * nel,char ** vec_lab)28 void NI_set_attribute_from_veclab_array( NI_element *nel , char **vec_lab )
29 {
30 char *vla ; int nvla , ii ;
31
32 if( NI_element_type(nel) != NI_ELEMENT_TYPE || nel->vec_num == 0 ) return ;
33
34 if( vec_lab == NULL ) vec_lab = nel->vec_lab ;
35 if( vec_lab == NULL ) return ;
36
37 for( nvla=ii=0 ; ii < nel->vec_num ; ii++ )
38 nvla += NI_strlen(vec_lab[ii])+8 ;
39
40 vla = (char *)malloc(sizeof(char)*nvla) ; vla[0] = '\0' ;
41 for( ii=0 ; ii < nel->vec_num ; ii++ ){
42 sprintf( vla+strlen(vla) , "%s%s" ,
43 (vec_lab[ii] != NULL) ? vec_lab[ii] : "\0" ,
44 (ii < nel->vec_num-1) ? "," : "\0" ) ;
45 }
46
47 NI_set_attribute(nel,"ni_veclab",vla) ;
48 free(vla) ;
49 return ;
50 }
51
52 /*-----------------------------------------------------------------------*/
53 /*! Construct an empty data element from a header.
54 - The data vectors will have space allocated, but they will be
55 filled with all zero bytes.
56 - If the header was "empty" (ended in "/>"), then no vectors will
57 be allocated, and nel->vec_num=0.
58 - This function is used by NI_read_element() to create the
59 data element after the header has been parsed.
60 - 27 Mar 2003: modified to allow vec_len=0, indicating vector
61 length to be inferred from amount of data
62 -------------------------------------------------------------------------*/
63
make_empty_data_element(header_stuff * hs)64 NI_element * make_empty_data_element( header_stuff *hs )
65 {
66 NI_element *nel ;
67 int ii ;
68
69 if( hs == NULL || hs->name == NULL ) return NULL ;
70
71 #ifdef NIML_DEBUG
72 NI_dpr("ENTER make_empty_data_element\n") ;
73 #endif
74
75 nel = NI_malloc(NI_element, sizeof(NI_element) ) ;
76
77 nel->type = NI_ELEMENT_TYPE ;
78
79 nel->outmode = -1 ; /* 29 Mar 2005 */
80
81 /* move name and attributes from hs to new element */
82
83 nel->name = hs->name ; hs->name = NULL ;
84
85 nel->attr_num = hs->nattr ;
86
87 if( nel->attr_num > 0 ){
88 nel->attr_lhs = hs->lhs ; hs->lhs = NULL ;
89 nel->attr_rhs = hs->rhs ; hs->rhs = NULL ;
90 } else {
91 nel->attr_lhs = nel->attr_rhs = NULL ;
92 }
93
94 /* set default vector parameters [indicating no data] */
95
96 nel->vec_num = 0 ;
97 nel->vec_len = 0 ;
98 nel->vec_typ = NULL ;
99 nel->vec = NULL ;
100 nel->vec_lab = NULL ; /* 11 Sep 2018 */
101 nel->filename= NULL ; /* 16 Jun 2020 */
102
103 nel->vec_filled = 0 ; /* no data has been filled into vectors */
104
105 nel->vec_rank = 0 ;
106 nel->vec_axis_len = NULL ;
107 nel->vec_axis_delta = NULL ;
108 nel->vec_axis_origin = NULL ;
109 nel->vec_axis_unit = NULL ;
110 nel->vec_axis_label = NULL ;
111
112 if( !hs->empty ){ /* find and process ni_* attributes about vectors */
113
114 /* ni_type attribute: set types of vectors */
115
116 ii = string_index( "ni_type" , nel->attr_num , nel->attr_lhs ) ;
117
118 if( ii >= 0 && nel->attr_rhs[ii] != NULL ){
119 int_array *iar = decode_type_string( nel->attr_rhs[ii] ) ;
120 if( iar != NULL ){
121 nel->vec_num = iar->num ; /* number of vectors */
122 nel->vec_typ = iar->ar ; /* vector types */
123 NI_free(iar) ; /* just the shell of the struct */
124 }
125 }
126
127 /* ni_dimen attribute: set vector length and rank */
128
129 ii = string_index( "ni_dimen" , nel->attr_num , nel->attr_lhs ) ;
130
131 if( ii >= 0 && nel->attr_rhs[ii] != NULL ){
132 int_array *dar = decode_dimen_string( nel->attr_rhs[ii] ) ;
133 if( dar != NULL && dar->num > 0 ){
134 int nd=dar->num , qq,pp ;
135 /* compute product of all dimensions */
136 for( qq=1,pp=0 ; pp < nd ; pp++ ) qq *= dar->ar[pp] ;
137 nel->vec_len = qq ; /* length of vectors */
138 nel->vec_rank = nd ; /* number of dimensions */
139 nel->vec_axis_len = dar->ar ; /* array of dimension lengths */
140 NI_free(dar) ; /* just the struct shell */
141 if( nel->vec_len == 0 ) /* 27 Mar 2003 */
142 nel->vec_rank = 1 ;
143 }
144 }
145
146 /* if we had ni_dimen, also try ni_delta */
147
148 ii = string_index( "ni_delta" , nel->attr_num , nel->attr_lhs ) ;
149 if( ii >= 0 && nel->vec_rank > 0 ){
150 NI_str_array *sar = NI_decode_string_list( nel->attr_rhs[ii] , NULL ) ;
151 if( sar != NULL && sar->num > 0 ){
152 int ns=sar->num , nd=nel->vec_rank , pp ;
153 nel->vec_axis_delta = NI_malloc(float,sizeof(float)*nd) ;
154 if( nd > ns ) nd = ns ;
155 for( pp=0 ; pp < nd ; pp++ )
156 sscanf( sar->str[pp] , "%f" , nel->vec_axis_delta+pp ) ;
157 NI_delete_str_array(sar) ;
158 }
159 }
160
161 /* if we had ni_dimen, also try ni_origin */
162
163 ii = string_index( "ni_origin" , nel->attr_num , nel->attr_lhs ) ;
164 if( ii >= 0 && nel->vec_rank > 0 ){
165 NI_str_array *sar = NI_decode_string_list( nel->attr_rhs[ii] , NULL ) ;
166 if( sar != NULL && sar->num > 0 ){
167 int ns=sar->num , nd=nel->vec_rank , pp ;
168 nel->vec_axis_origin = NI_malloc(float,sizeof(float)*nd) ;
169 if( nd > ns ) nd = ns ;
170 for( pp=0 ; pp < nd ; pp++ )
171 sscanf( sar->str[pp] , "%f" , nel->vec_axis_origin+pp ) ;
172 NI_delete_str_array(sar) ;
173 }
174 }
175
176 /* if we had ni_dimen, also try ni_units */
177
178 ii = string_index( "ni_units" , nel->attr_num , nel->attr_lhs ) ;
179 if( ii >= 0 && nel->vec_rank > 0 ){
180 NI_str_array *sar = NI_decode_string_list( nel->attr_rhs[ii] , NULL ) ;
181 if( sar != NULL && sar->num > 0 ){
182 int ns=sar->num , nd=nel->vec_rank , pp ;
183 nel->vec_axis_unit = NI_malloc(char*,sizeof(char *)*nd) ;
184 if( nd > ns ) nd = ns ;
185 for( pp=0 ; pp < nd ; pp++ )
186 nel->vec_axis_unit[pp] = NI_strdup(sar->str[pp]) ;
187 NI_delete_str_array(sar) ;
188 }
189 }
190
191 /* if we had ni_dimen, also try ni_axes */
192
193 ii = string_index( "ni_axes" , nel->attr_num , nel->attr_lhs ) ;
194 if( ii >= 0 && nel->vec_rank > 0 ){
195 NI_str_array *sar = NI_decode_string_list( nel->attr_rhs[ii] , NULL ) ;
196 if( sar != NULL && sar->num > 0 ){
197 int ns=sar->num , nd=nel->vec_rank , pp ;
198 nel->vec_axis_label = NI_malloc(char*,sizeof(char *)*nd) ;
199 if( nd > ns ) nd = ns ;
200 for( pp=0 ; pp < nd ; pp++ )
201 nel->vec_axis_label[pp] = NI_strdup(sar->str[pp]) ;
202 NI_delete_str_array(sar) ;
203 }
204 }
205
206 /* see if we have vector label strings [11 Sep 2018] */
207
208 ii = string_index( "ni_veclab" , nel->attr_num , nel->attr_lhs ) ;
209 if( nel->vec_num > 0 && ii > 0 ){
210 NI_set_veclab_from_stringlist( nel , nel->attr_rhs[ii] ) ;
211 }
212
213 /* supply vector parameters if none was given */
214 /* (remember, we DON'T have an empty element) */
215
216 if( nel->vec_num == 0 ){ /* default type */
217 nel->vec_num = 1 ;
218 nel->vec_typ = NI_malloc(int,sizeof(int)) ;
219 nel->vec_typ[0] = NI_BYTE ;
220 }
221
222 if( nel->vec_rank == 0 ){ /* default dimensions */
223 nel->vec_len = 0 ;
224 nel->vec_rank = 1 ;
225 nel->vec_axis_len = NI_malloc(int, sizeof(int)) ;
226 nel->vec_axis_len[0] = 1 ;
227 }
228
229 /* now allocate space for vectors defined above */
230
231 nel->vec = NI_malloc(void*, sizeof(void *)*nel->vec_num ) ;
232
233 /* 27 Mar 2003: only allocate space if we know how long they are */
234
235 if( nel->vec_len > 0 ){
236 for( ii=0 ; ii < nel->vec_num ; ii++ )
237 nel->vec[ii] = NI_malloc(void,
238 NI_type_size(nel->vec_typ[ii])*nel->vec_len) ;
239 } else {
240 for( ii=0 ; ii < nel->vec_num ; ii++ )
241 nel->vec[ii] = NULL ;
242 }
243
244 } /* end of processing non-empty header stuff */
245
246 return nel ;
247 }
248
249 /*-------------------------------------------------------------------------*/
250 /*! Make an empty group element from parsed header info.
251 The attributes in the header are assigned to the group, and the group
252 parts are initialized to nothing.
253 ---------------------------------------------------------------------------*/
254
make_empty_group_element(header_stuff * hs)255 NI_group * make_empty_group_element( header_stuff *hs )
256 {
257 NI_group *ngr ;
258
259 if( hs == NULL || hs->name == NULL ) return NULL ;
260
261 ngr = NI_malloc(NI_group, sizeof(NI_group) ) ;
262
263 ngr->type = NI_GROUP_TYPE ;
264
265 ngr->name = hs->name ; hs->name = NULL ; /* 24 Feb 2005 */
266
267 ngr->outmode = -1 ; /* 29 Mar 2005 */
268
269 /* move attributes from hs to new element */
270
271 ngr->attr_num = hs->nattr ;
272
273 if( ngr->attr_num > 0 ){
274 ngr->attr_lhs = hs->lhs ; hs->lhs = NULL ;
275 ngr->attr_rhs = hs->rhs ; hs->rhs = NULL ;
276 } else {
277 ngr->attr_lhs = ngr->attr_rhs = NULL ;
278 }
279
280 /* have no pieces-parts yet */
281
282 ngr->part_num = 0 ;
283 ngr->part_typ = NULL ;
284 ngr->part = NULL ;
285 ngr->filename = NULL ; /* 16 Jun 2020 */
286
287 return ngr ;
288 }
289
290 /*-------------------------------------------------------------------------*/
291 /*! Byte size of a given integer type code.
292 Modified 13 Feb 2003 to use the new rowtype stuff.
293 ---------------------------------------------------------------------------*/
294
NI_type_size(int tval)295 int NI_type_size( int tval )
296 {
297 int ii = NI_rowtype_code_to_size( tval ) ;
298 return (ii > 0) ? ii : 0 ;
299 }
300
301 /*************************************************************************/
302 /********** Functions to create NIML data and group elements *************/
303 /*************************************************************************/
304
305 /*-----------------------------------------------------------------------*/
306 /*! Return the type of something that points to a NI element.
307 - The input should be point to a NI_element, NI_group, or NI_procins.
308 - The return value is NI_ELEMENT_TYPE, NI_GROUP_TYPE, NI_PROCINS_TYPE,
309 or -1 if the type is anything else or unknowable.
310 -------------------------------------------------------------------------*/
311
NI_element_type(void * nini)312 int NI_element_type( void *nini )
313 {
314 NI_element *nel = (NI_element *) nini ;
315 NI_group *ngr = (NI_group *) nini ;
316 NI_procins *npi = (NI_procins *) nini ; /* 16 Mar 2005 */
317
318 if( nini == NULL ) return -1 ;
319
320 if( nel->type == NI_ELEMENT_TYPE ) return NI_ELEMENT_TYPE ;
321 if( ngr->type == NI_GROUP_TYPE ) return NI_GROUP_TYPE ;
322 if( npi->type == NI_PROCINS_TYPE ) return NI_PROCINS_TYPE ;
323
324 return -1 ;
325 }
326
327 /*-----------------------------------------------------------------------*/
328 /*! Return the name of a NI element. If the input is bad, returns
329 a NULL pointer. Do not free this pointer! It points to the
330 name string inside the element struct.
331 -------------------------------------------------------------------------*/
332
NI_element_name(void * nini)333 char * NI_element_name( void *nini )
334 {
335 NI_element *nel = (NI_element *) nini ;
336 NI_group *ngr = (NI_group *) nini ;
337 NI_procins *npi = (NI_procins *) nini ;
338
339 if( nini == NULL ) return NULL ;
340
341 if( nel->type == NI_ELEMENT_TYPE ) return nel->name ;
342 if( ngr->type == NI_GROUP_TYPE ) return ngr->name ;
343 if( npi->type == NI_PROCINS_TYPE ) return npi->name ;
344
345 return NULL ;
346 }
347
348 /*-----------------------------------------------------------------------*/
349 /*! Expunge a data or group element and its contents from the universe.
350 -------------------------------------------------------------------------*/
351
NI_free_element(void * nini)352 void NI_free_element( void *nini )
353 {
354 int ii , tt=NI_element_type(nini) ;
355
356 if( tt < 0 ) return ; /* bad input */
357
358 /*-- erase contents of data element --*/
359
360 if( tt == NI_ELEMENT_TYPE ){
361 NI_element *nel = (NI_element *)nini ;
362
363 NI_free(nel->name) ;
364 for( ii=0 ; ii < nel->attr_num ; ii++ ){
365 NI_free( nel->attr_lhs[ii] ) ;
366 NI_free( nel->attr_rhs[ii] ) ;
367 }
368 NI_free( nel->attr_lhs ) ;
369 NI_free( nel->attr_rhs ) ;
370
371 /* 14 Feb 2003: NI_free_column() will also free var dim arrays */
372
373 if( nel->vec != NULL ){
374 for( ii=0 ; ii < nel->vec_num ; ii++ ){
375 NI_free_column( NI_rowtype_find_code(nel->vec_typ[ii]) ,
376 nel->vec_len , nel->vec[ii] ) ;
377 }
378 }
379
380 NI_free( nel->vec_typ ) ;
381 NI_free( nel->vec ) ;
382
383 NI_free(nel->vec_axis_len) ;
384 NI_free(nel->vec_axis_delta) ;
385 NI_free(nel->vec_axis_origin) ;
386 NI_free(nel->vec_axis_unit) ;
387 NI_free(nel->vec_axis_label) ;
388
389 if( nel->vec_lab != NULL ){ /* 12 Sep 2018 */
390 for( ii=0 ; ii < nel->vec_num ; ii++ ) NI_free(nel->vec_lab[ii]) ;
391 NI_free(nel->vec_lab) ;
392 }
393
394 NI_free( nel->filename ) ; /* 16 Jun 2020 */
395
396 NI_free( nel ) ;
397
398 /*-- erase contents of group element --*/
399
400 } else if( tt == NI_GROUP_TYPE ){
401 NI_group *ngr = (NI_group *)nini ;
402
403 for( ii=0 ; ii < ngr->attr_num ; ii++ ){
404 NI_free( ngr->attr_lhs[ii] ) ;
405 NI_free( ngr->attr_rhs[ii] ) ;
406 }
407 NI_free( ngr->attr_lhs ) ;
408 NI_free( ngr->attr_rhs ) ;
409
410 if( ngr->part != NULL ){
411 for( ii=0 ; ii < ngr->part_num ; ii++ )
412 NI_free_element( ngr->part[ii] ) ; /* recursion */
413 }
414
415 NI_free( ngr->part_typ ) ;
416 NI_free( ngr->part ) ;
417 NI_free( ngr->name ) ; /* 03 Jun 2002 */
418 NI_free( ngr->filename ); /* 16 Jun 2020 */
419 NI_free( ngr ) ;
420
421 /*-- erase contents of processing instruction --*/
422
423 } else if( tt == NI_PROCINS_TYPE ){
424 NI_procins *npi = (NI_procins *)nini ;
425
426 for( ii=0 ; ii < npi->attr_num ; ii++ ){
427 NI_free( npi->attr_lhs[ii] ) ;
428 NI_free( npi->attr_rhs[ii] ) ;
429 }
430 NI_free( npi->attr_lhs ) ;
431 NI_free( npi->attr_rhs ) ;
432
433 NI_free( npi->name ) ; /* 03 Jun 2002 */
434 NI_free( npi ) ;
435 }
436
437 return ;
438 }
439
440 /*-----------------------------------------------------------------------*/
441 /*! Expunge all data from element or group. 17 Jul 2006 [rickr]
442 -------------------------------------------------------------------------*/
443
NI_free_element_data(void * nini)444 void NI_free_element_data( void *nini )
445 {
446 int ii , tt=NI_element_type(nini) ;
447
448 if( tt < 0 ) return ; /* bad input */
449
450 /*-- if element, nuke data --*/
451
452 if( tt == NI_ELEMENT_TYPE ){
453 NI_element *nel = (NI_element *)nini ;
454
455 if( nel->vec != NULL ){
456 for( ii=0 ; ii < nel->vec_num ; ii++ )
457 NI_free_column( NI_rowtype_find_code(nel->vec_typ[ii]) ,
458 nel->vec_len , nel->vec[ii] ) ;
459 NI_free( nel->vec ) ;
460 nel->vec = NULL ;
461 }
462
463 /*-- if group, recur --*/
464
465 } else if( tt == NI_GROUP_TYPE ){
466 NI_group *ngr = (NI_group *)nini ;
467
468 if( ngr->part != NULL ){
469 for( ii=0 ; ii < ngr->part_num ; ii++ )
470 NI_free_element_data( ngr->part[ii] ) ; /* recursion */
471 }
472 }
473
474 /*-- no other cases for data --*/
475
476 return ;
477 }
478
479 /*-----------------------------------------------------------------------*/
480
NI_init_veclen(NI_element * nel,int veclen)481 static void NI_init_veclen( NI_element *nel , int veclen )
482 {
483 if( veclen == 0 ){ /* empty element */
484 nel->vec_len = 0 ;
485 nel->vec_filled = 0 ;
486 nel->vec_rank = 0 ;
487 nel->vec_axis_len = NULL ;
488 } else { /* element with data to */
489 nel->vec_len = veclen ; /* come via NI_add_column */
490 nel->vec_filled = veclen ;
491 nel->vec_rank = 1 ;
492 nel->vec_axis_len = NI_malloc(int, sizeof(int)) ;
493 nel->vec_axis_len[0] = veclen ;
494 }
495 }
496
497 /*-----------------------------------------------------------------------*/
498 /*! Create a new data element.
499
500 - name = string name for header.
501 - veclen = size (length) of vectors (ni_dimen attribute).
502 - Vectors are added with NI_add_column().
503 - Set this to zero for "empty" elements (those with only
504 headers, no data).
505
506 Return is NULL if inputs are stupid or criminal or insane.
507 -------------------------------------------------------------------------*/
508
NI_new_data_element(char * name,int veclen)509 NI_element * NI_new_data_element( char *name , int veclen )
510 {
511 NI_element *nel ;
512
513 if( name == NULL || name[0] == '\0' || veclen < 0 ) return NULL ;
514
515 nel = NI_malloc(NI_element, sizeof(NI_element) ) ;
516
517 nel->type = NI_ELEMENT_TYPE ; /* mark as being a data element */
518
519 nel->outmode = -1 ; /* 29 Mar 2005 */
520
521 nel->name = NI_strdup(name) ;
522 nel->attr_num = 0 ;
523 nel->attr_lhs = nel->attr_rhs = NULL ; /* no attributes yes */
524
525 nel->vec_num = 0 ; /* no vectors yet */
526 nel->vec_typ = NULL ;
527 nel->vec = NULL ;
528 nel->vec_lab = NULL ; /* 11 Sep 2018 */
529 nel->filename= NULL ; /* 16 Jun 2020 */
530
531 NI_init_veclen( nel , veclen ) ; /* 19 Sep 2008 */
532
533 nel->vec_axis_delta = NULL ;
534 nel->vec_axis_origin = NULL ;
535 nel->vec_axis_unit = NULL ;
536 nel->vec_axis_label = NULL ;
537
538 return nel ;
539 }
540
541 /*-----------------------------------------------------------------------*/
542 /*! Insert a label for column #cc into a data element.
543 Note that if column #cc does not exist, nothing will happen,
544 so this function should be called AFTER NI_add_column(). [11 Sep 2018]
545 -------------------------------------------------------------------------*/
546
NI_set_column_label(NI_element * nel,int cc,char * lab)547 void NI_set_column_label( NI_element *nel , int cc , char *lab )
548 {
549
550 if( nel == NULL || nel->vec_len <= 0 ) return ;
551 if( nel->type != NI_ELEMENT_TYPE ) return ;
552 if( cc < 0 || cc >= nel->vec_num || lab == NULL ) return ;
553
554 if( nel->vec_lab == NULL ){ /* create empty label array */
555 int pp ;
556 nel->vec_lab = (char **)NI_malloc(char*,sizeof(char *)*nel->vec_num) ;
557 for( pp=0 ; pp < nel->vec_num ; pp++ ) nel->vec_lab[pp] = NI_strdup("\0") ;
558 }
559
560 if( nel->vec_lab[cc] != NULL ) NI_free(nel->vec_lab[cc]) ;
561 nel->vec_lab[cc] = NI_strdup(lab) ;
562 return ;
563 }
564
565 /*-----------------------------------------------------------------------*/
566 /*! Add a vector (column) of data to a data element.
567
568 - nel = data element to modify
569 - typ = integer type code of data (e.g., NI_FLOAT)
570 - arr = pointer to data values - must be an array of length veclen
571 (same value as used in NI_new_data_element() call)
572 - if arr is NULL, then will add a zero-filled column of the given
573 type to the data element
574
575 The data array is copied into the element. If the element was
576 specified with veclen=0, then this function will do nothing.
577 Since this function has no return value, the only way to check for
578 such an error is to see if nel->vec_num was incremented. Or don't
579 be so stupid as to make this error.
580 -------------------------------------------------------------------------*/
581
NI_add_column(NI_element * nel,int typ,void * arr)582 void NI_add_column( NI_element *nel , int typ , void *arr )
583 {
584 int nn ;
585 NI_rowtype *rt ;
586
587 /* check for reasonable inputs */
588
589 if( nel == NULL || nel->vec_len <= 0 ) return ;
590 if( nel->type != NI_ELEMENT_TYPE ) return ;
591 rt = NI_rowtype_find_code(typ) ; if( rt == NULL ) return ;
592
593 /* get number of vectors currently in element */
594
595 nn = nel->vec_num ;
596
597 /* add 1 to the vec_typ array */
598
599 nel->vec_typ = NI_realloc( nel->vec_typ, int, sizeof(int)*(nn+1) ) ;
600 nel->vec_typ[nn] = typ ;
601
602 /* add 1 element to the vec array, and copy data into it */
603
604 nel->vec = NI_realloc( nel->vec , void*, sizeof(void *)*(nn+1) ) ;
605 if( arr != NULL )
606 nel->vec[nn] = NI_copy_column( rt , nel->vec_len , arr ) ;
607 else
608 nel->vec[nn] = NI_malloc(void, rt->size * nel->vec_len ) ;
609
610 if( nel->vec_lab != NULL ){ /* 11 Sep 2018 */
611 nel->vec_lab = NI_realloc( nel->vec_lab , char* , sizeof(char *)*(nn+1) ) ;
612 nel->vec_lab[nn] = NI_strdup("\0") ;
613 }
614
615 /* add 1 to the count of vectors */
616
617 nel->vec_num = nn+1 ;
618
619 /* if element has "ni_type" attribute, adjust it 14 Jul 2006 [rickr] */
620 if( NI_get_attribute(nel, "ni_type") )
621 NI_set_ni_type_atr(nel) ;
622
623 return ;
624 }
625
626 /*-------------------------------------------------------------------------*/
627 /*!
628 Like add_column, but inserts the column at nel->vec[icol] rather than
629 at the end.
630 if icol < 0 || icol > nel->vec_num then icol = nel->vec_num
631 */
NI_insert_column(NI_element * nel,int typ,void * arr,int icol)632 void NI_insert_column( NI_element *nel , int typ , void *arr, int icol )
633 {
634 int nn, ii ;
635 NI_rowtype *rt ;
636
637 /* check for reasonable inputs */
638
639 if( nel == NULL || nel->vec_len <= 0 ) return ;
640 if( nel->type != NI_ELEMENT_TYPE ) return ;
641 rt = NI_rowtype_find_code(typ) ; if( rt == NULL ) return ;
642
643 /* get number of vectors currently in element */
644 nn = nel->vec_num ;
645
646 if (icol > nn || icol < 0) icol = nn;
647
648 /* call add column */
649 NI_add_column(nel, typ, arr);
650
651 /* check on success */
652 if (nel->vec_num != nn+1) return ; /* misere */
653 nn = nel->vec_num ; /* the new number of vectors */
654
655 NI_move_column(nel, nn-1, icol);
656
657 return ;
658 }
659
660 /*-------------------------------------------------------------------------*/
661 /*!
662 move a column from index ibefore to iafter
663 if ibefore (or iafter) is (< 0 || > nel->vec_num) then
664 ibefore (or iafter) = nel->vec_num-1
665 */
NI_move_column(NI_element * nel,int ibefore,int iafter)666 void NI_move_column(NI_element *nel, int ibefore, int iafter)
667 {
668 int nn, ii ;
669 int typ_buf;
670 void *col_buf;
671 char *lab_buf=NULL ; /* 11 Sep 2018 */
672
673 if (nel == NULL || nel->vec_len <= 0 ) return ;
674
675 nn = nel->vec_num ;
676 if (ibefore < 0 || ibefore >= nn) ibefore = nn-1;
677 if (iafter < 0 || iafter >= nn) iafter = nn-1;
678
679 /* nothing to see here? */
680 if (ibefore == iafter) return;
681
682 /* do the deed */
683 /* store the initial values */
684 typ_buf = nel->vec_typ[ibefore];
685 col_buf = nel->vec[ibefore];
686 if( nel->vec_lab != NULL ) lab_buf = nel->vec_lab[ibefore] ;
687 /* shift */
688 if (ibefore > iafter) {
689 /* shift columns to left*/
690 for (ii=ibefore; ii > iafter; --ii) {
691 nel->vec[ii] = nel->vec[ii-1];
692 nel->vec_typ[ii] = nel->vec_typ[ii-1];
693 if( nel->vec_lab != NULL )
694 nel->vec_lab[ii] = nel->vec_lab[ii-1] ;
695 }
696 } else {
697 /* shift columns to right*/
698 for (ii=ibefore; ii < iafter; ++ii) {
699 nel->vec[ii] = nel->vec[ii+1];
700 nel->vec_typ[ii] = nel->vec_typ[ii+1];
701 if( nel->vec_lab != NULL )
702 nel->vec_lab[ii] = nel->vec_lab[ii+1] ;
703 }
704 }
705
706 /* insert the trouble maker back*/
707 nel->vec[iafter] = col_buf;
708 nel->vec_typ[iafter] = typ_buf;
709 if( nel->vec_lab != NULL )
710 nel->vec_lab[iafter] = lab_buf ;
711
712 /* house keeping */
713 /* if element has "ni_type" attribute, adjust it 14 Jul 2006 [rickr] */
714 if( NI_get_attribute(nel, "ni_type") )
715 NI_set_ni_type_atr(nel) ;
716
717 return ;
718 }
719
720 /*-------------------------------------------------------------------------*/
721 /*!
722 Do we really need to document this too? [[Cox says YES]]
723 Removes column irm from nel. If irm < 0 or
724 irm >= nel->vec_num irm = nel->vec_num -1
725 */
NI_remove_column(NI_element * nel,int irm)726 void NI_remove_column(NI_element *nel, int irm)
727 {
728 int nn;
729
730 if (nel == NULL || nel->vec_len <= 0 ) return ;
731
732 if (!(nn = nel->vec_num)) return;
733
734 if (irm < 0 || irm >= nn) irm = nn-1;
735
736 /* move irm to last column */
737 NI_move_column(nel, irm, -1);
738
739 /* free the last column */
740 NI_free_column( NI_rowtype_find_code(nel->vec_typ[nn-1]) ,
741 nel->vec_len , nel->vec[nn-1] ) ;
742 nel->vec[nn-1] = NULL; /* to be sure */
743
744 /* decrease the number of columns */
745 --nn;
746 nel->vec_num = nn;
747
748 /* get rid of extra space */
749 nel->vec_typ = NI_realloc( nel->vec_typ, int, sizeof(int)*(nn) ) ;
750 nel->vec = NI_realloc( nel->vec , void*, sizeof(void *)*(nn) ) ;
751 if( nel->vec_lab != NULL )
752 nel->vec_lab = NI_realloc( nel->vec_lab , char*, sizeof(char *)*(nn) ) ;
753
754 /* if element has "ni_type" attribute, adjust it 14 Jul 2006 [rickr] */
755 if( NI_get_attribute(nel, "ni_type") )
756 NI_set_ni_type_atr(nel) ;
757
758 return;
759 }
760
761 /*------------------------------------------------------------------------*/
762 /*! Change the length of all the columns in a data element.
763 - If the columns are longer, they will be zero filled.
764 - New values can be inserted later with NI_insert_value().
765 - If the columns are shorter, data will be lost.
766 - You can use this to convert an element from empty to non-empty
767 by entering newlen > 0 when the original vec_len is 0.
768 - But, you cannot use this to convert an element to empty from
769 non-empty, by entering newlen == 0 when vec_len > 0!
770 --------------------------------------------------------------------------*/
771
NI_alter_veclen(NI_element * nel,int newlen)772 void NI_alter_veclen( NI_element *nel , int newlen )
773 {
774 int oldlen , ii ;
775 NI_rowtype *rt ;
776 char *pt ;
777
778 if( nel == NULL || nel->type != NI_ELEMENT_TYPE ) return ;
779 if( newlen <= 0 ) return ;
780
781 if( nel->vec_num == 0 ){ /* if have no data yet */
782 nel->vec_len = nel->vec_filled = newlen; return;
783 }
784
785 if( nel->vec_len == 0 ) NI_init_veclen( nel , newlen ) ; /* 19 Sep 2008 */
786
787 oldlen = nel->vec_len ; if( oldlen == newlen ) return ;
788
789 for( ii=0 ; ii < nel->vec_num ; ii++ ){
790 rt = NI_rowtype_find_code( nel->vec_typ[ii] ) ;
791 nel->vec[ii] = NI_realloc( nel->vec[ii] , void , rt->size * newlen ) ;
792 if( oldlen < newlen ){
793 pt = ((char *)nel->vec[ii]) + (rt->size * oldlen) ; /* zero fill */
794 memset( pt , 0 , (newlen-oldlen)*rt->size ) ; /* new data! */
795 }
796 }
797
798 nel->vec_len = nel->vec_filled = newlen ; return ;
799 }
800
801 /*------------------------------------------------------------------------*/
802 /*! As in NI_add_column(), but adding every stride-th element from arr.
803 Thus, arr should be at least nel->vec_len * stride elements long.
804 --------------------------------------------------------------------------*/
805
NI_add_column_stride(NI_element * nel,int typ,void * arr,int stride)806 void NI_add_column_stride( NI_element *nel, int typ, void *arr, int stride )
807 {
808 int nn , ii ;
809 NI_rowtype *rt ;
810 char *idat ;
811
812 /* check for reasonable inputs */
813
814 if( nel == NULL || nel->vec_len <= 0 ) return ;
815 if( nel->type != NI_ELEMENT_TYPE ) return ;
816 rt = NI_rowtype_find_code(typ) ; if( rt == NULL ) return ;
817
818 /* add an empty column */
819
820 NI_add_column( nel , typ , NULL ) ;
821 if( arr == NULL ) return ; /* no input data ==> we're done */
822
823 /* loop over inputs and put them in one at a time */
824
825 nn = nel->vec_num-1 ;
826 idat = (char *) arr ;
827
828 for( ii=0 ; ii < nel->vec_len ; ii++ )
829 NI_insert_value( nel , ii , nn , idat + (ii*stride*rt->size) ) ;
830
831 return ;
832 }
833
834 /*-------------------------------------------------------------------------*/
835 /*!
836 See NI_insert_column for inspiration
837 */
NI_insert_column_stride(NI_element * nel,int typ,void * arr,int stride,int icol)838 void NI_insert_column_stride( NI_element *nel, int typ, void *arr, int stride, int icol )
839 {
840 int nn , ii ;
841 NI_rowtype *rt ;
842 char *idat ;
843
844 /* check for reasonable inputs */
845
846 if( nel == NULL || nel->vec_len <= 0 ) return ;
847 if( nel->type != NI_ELEMENT_TYPE ) return ;
848 rt = NI_rowtype_find_code(typ) ; if( rt == NULL ) return ;
849
850 /* get number of vectors currently in element */
851 nn = nel->vec_num ;
852
853 if (icol > nn || icol < 0) icol = nn;
854
855 /* call add column_stride */
856 NI_add_column_stride(nel, typ, arr, stride);
857
858 /* check on success */
859 if (nel->vec_num != nn+1) return ; /* misere */
860 nn = nel->vec_num ; /* the new number of vectors */
861
862 NI_move_column(nel, nn-1, icol);
863
864 return ;
865 }
866
867
868 /*------------------------------------------------------------------------*/
869 /*! ZSS; Fills an already created column with values up to vec_filled
870 the values in arr are inserted into nel->vec[nn]
871 --------------------------------------------------------------------------*/
872
NI_fill_column_stride(NI_element * nel,int typ,void * arr,int nn,int stride)873 void NI_fill_column_stride( NI_element *nel, int typ,
874 void *arr, int nn, int stride )
875 {
876 int ii , nf;
877 NI_rowtype *rt ;
878 char *idat ;
879
880 /* check for reasonable inputs */
881
882 if( nel == NULL || nel->vec_len <= 0 ) return ;
883 if( nel->type != NI_ELEMENT_TYPE ) return ;
884 rt = NI_rowtype_find_code(typ) ; if( rt == NULL ) return ;
885
886 /* check for NULL column or other similar errors*/
887
888 if( arr == NULL ) return ;
889 if( nel->vec[nn] == NULL ) return ;
890 if( nn < 0 || nn >= nel->vec_num ) return ;
891 if( typ != nel->vec_typ[nn] ) return ;
892
893 /* loop over inputs and put them in */
894
895 if( nel->vec_filled > 0 && nel->vec_filled <= nel->vec_len )
896 nf = nel->vec_filled ;
897 else
898 nf = nel->vec_len ;
899
900 idat = (char *) arr ;
901
902 for( ii=0 ; ii < nf ; ii++ )
903 NI_insert_value( nel , ii , nn , idat + (ii*stride*rt->size) ) ;
904
905 return ;
906 }
907
908 /*------------------------------------------------------------------------*/
909 /*! Replace the row-th value in the col-th column of the data element.
910 - dat is the pointer to the data values to copy into the element.
911 - The column must have been created with NI_add_column() before
912 calling this function!
913 - NOTE WELL: When the column type is NI_STRING, it is a mistake
914 to call this function with dat being a pointer to the C string
915 to insert. Instead, dat should be a pointer to the pointer to
916 the C string. For example:
917 - char *me = "RWCox" ;
918 - WRONG: NI_insert_value ( nel, 3,5, me ) ; [Seg Fault ensues]
919 - RIGHT: NI_insert_value ( nel, 3,5, &me ) ;
920 - RIGHT: NI_insert_string( nel, 3,5, me ) ;
921 - The last case illustrates the NI_insert_string() function,
922 which can be used to simplify insertion into a column
923 of Strings; that function is just a simple wrapper to call
924 NI_insert_value() properly.
925 - The reason the first example is WRONG is that dat is supposed
926 to point to the data to be stored. In the case of a String,
927 the data is the pointer to the C string.
928 --------------------------------------------------------------------------*/
929
NI_insert_value(NI_element * nel,int row,int col,void * dat)930 void NI_insert_value( NI_element *nel, int row, int col, void *dat )
931 {
932 NI_rowtype *rt ;
933 char *cdat , *idat=(char *)dat , *qpt ;
934 int jj , kk ;
935
936 /* check for reasonable inputs */
937
938 if( nel == NULL || idat == NULL ) return ;
939 if( nel->type != NI_ELEMENT_TYPE ) return ;
940 if( nel->vec_len <= 0 ) return ;
941 if( row < 0 || row >= nel->vec_len ) return ;
942 if( col < 0 || col >= nel->vec_num ) return ;
943
944 rt = NI_rowtype_find_code( nel->vec_typ[col] ) ;
945 if( rt == NULL ) return ;
946
947 cdat = (char *) nel->vec[col] ; /* points to column data */
948 cdat = cdat + rt->size * row ; /* points to data to alter */
949
950 /* shallow copy of input data over data now present */
951
952 memcpy( cdat , idat , rt->size ) ; /* cdat now contains input data */
953
954 /* copy any var dim arrays inside */
955
956 if( ROWTYPE_is_varsize(rt) ){
957 for( jj=0 ; jj < rt->part_num ; jj++ ){ /* loop over parts */
958
959 if( rt->part_typ[jj] == NI_STRING ){ /* a string part */
960 char **apt = (char **)(cdat+rt->part_off[jj]) ; /* *apt => input data */
961 qpt = NI_strdup(*apt) ; /* qpt = copy of input string */
962 *apt = qpt ; /* reset *apt to copy of input string */
963
964 } else if( rt->part_dim[jj] >= 0 ){ /* var dim array */
965 char **apt = (char **)(cdat+rt->part_off[jj]) ; /* *apt => data */
966 if( *apt != NULL ){
967 kk = ROWTYPE_part_dimen(rt,cdat,jj) * rt->part_rtp[jj]->size ;
968 qpt = NI_malloc(char, kk) ; memcpy(qpt,*apt,kk) ; *apt = qpt ;
969 }
970 }
971 }
972 }
973
974 return ;
975 }
976
977 /*------------------------------------------------------------------------*/
978
NI_insert_string(NI_element * nel,int row,int col,char * str)979 void NI_insert_string( NI_element *nel, int row, int col, char *str )
980 {
981 if( nel == NULL || str == NULL ) return ;
982 if( nel->type != NI_ELEMENT_TYPE ) return ;
983 if( row < 0 || row >= nel->vec_len ) return ;
984 if( col < 0 || col >= nel->vec_num ) return ;
985 if( nel->vec_typ[col] != NI_STRING ) return ;
986
987 NI_insert_value( nel , row,col , &str ); return ;
988 }
989
990 /*------------------------------------------------------------------------*/
991 /* Return a float value. If the data type does not pass NI_IS_NUMERIC_TYPE,
992 or if any other thing is non-copasetic, then return value is 0.0f.
993 *//*----------------------------------------------------------------------*/
994
NI_extract_float_value(NI_element * nel,int row,int col)995 float NI_extract_float_value( NI_element *nel , int row , int col )
996 {
997 char *cdat ;
998 NI_rowtype *rt ;
999
1000 /* check for stoopid stufff */
1001
1002 if( nel == NULL ) return 0.0f ;
1003 if( nel->type != NI_ELEMENT_TYPE ) return 0.0f ;
1004 if( row < 0 || row >= nel->vec_len ) return 0.0f ;
1005 if( col < 0 || col >= nel->vec_num ) return 0.0f ;
1006 if( ! NI_IS_NUMERIC_TYPE(nel->vec_typ[col]) ) return 0.0f ;
1007
1008 rt = NI_rowtype_find_code( nel->vec_typ[col] ) ;
1009 if( rt == NULL ) return 0.0f ;
1010
1011 cdat = (char *) nel->vec[col] ; /* points to column data */
1012 cdat = cdat + rt->size * row ; /* points to data to get */
1013
1014 switch( nel->vec_typ[col] ){
1015 default: return 0.0f ; /* should not happen */
1016
1017 case NI_FLOAT:{
1018 float *ar = (float *)cdat ; return ar[0] ;
1019 }
1020
1021 case NI_BYTE:{
1022 byte *ar = (byte *)cdat ; return (float)ar[0] ;
1023 }
1024
1025 case NI_SHORT:{
1026 short *ar = (short *)cdat ; return (float)ar[0] ;
1027 }
1028
1029 case NI_INT:{
1030 int *ar = (int *)cdat ; return (float)ar[0] ;
1031 }
1032
1033 case NI_DOUBLE:{
1034 double *ar = (double *)cdat ; return (float)ar[0] ;
1035 }
1036
1037 case NI_COMPLEX:{
1038 complex *ar = (complex *)cdat ;
1039 double x = (double)ar[0].r , y = (double)ar[0].i ;
1040 return (float)sqrt(x*x+y*y) ;
1041 }
1042
1043 case NI_RGB:{
1044 rgb *ar = (rgb *)cdat ;
1045 float rr = (float)ar[0].r, gg = (float)ar[0].g, bb = (float)ar[0].b ;
1046 return (0.299f*rr+0.587f*gg+0.114f*bb) ;
1047 }
1048
1049 case NI_RGBA:{
1050 rgba *ar = (rgba *)cdat ;
1051 float rr = (float)ar[0].r, gg = (float)ar[0].g, bb = (float)ar[0].b ;
1052 float aa = (float)ar[0].a ;
1053 return (0.299f*rr+0.587f*gg+0.114f*bb)*(aa/255.0f) ;
1054 }
1055
1056 }
1057
1058 return 0.0f ; /* unreachable */
1059 }
1060
1061 /*------------------------------------------------------------------------*/
1062 /* Return a malloc()-ed string value from one value in a data element.
1063 Adapted from NI_write_columns().
1064 Result should be free()-ed when you are done with it.
1065 [19 Jun 2020 - RWCox == NIMLman]
1066 *//*----------------------------------------------------------------------*/
1067
NI_extract_text_value(NI_element * nel,int row,int col)1068 char * NI_extract_text_value( NI_element *nel , int row , int col )
1069 {
1070 int fsiz , col_typ , ii ;
1071 NI_rowtype *rt ;
1072 char *ptr , *col_dat , *outstr ;
1073
1074 /* check for stoopid stufff */
1075
1076 if( nel == NULL ) return NULL ;
1077 if( nel->type != NI_ELEMENT_TYPE ) return NULL ;
1078 if( row < 0 || row >= nel->vec_len ) return NULL ;
1079 if( col < 0 || col >= nel->vec_num ) return NULL ;
1080
1081 col_typ = nel->vec_typ[col] ; /* type of data in column */
1082 rt = NI_rowtype_find_code( col_typ ) ;
1083 if( rt == NULL ) return NULL ; /* impossible? */
1084
1085 fsiz = rt->size ; /* fixed size of struct (w/padding) */
1086 col_dat = (char *)nel->vec[col] ; /* ptr to column data */
1087 ptr = col_dat + fsiz*row ; /* ptr to row-th struct in column */
1088
1089 outstr = (char *)malloc(sizeof(char)*999*rt->part_num) ; outstr[0] = '\0' ;
1090
1091 /* write each part of this struct into the buffer */
1092
1093 for( ii=0 ; ii < rt->part_num ; ii++ ){ /*-- loop over parts --*/
1094
1095 if( rt->part_dim[ii] < 0 ){ /*-- a single value --*/
1096 NI_val_to_text( rt->part_rtp[ii],
1097 ptr+rt->part_off[ii], outstr ) ;
1098 } else { /* a compound data type with variable size data */
1099 int dim ;
1100 char **apt = (char **)(ptr+rt->part_off[ii]); /* data in struct */
1101 /* is ptr to array */
1102
1103 dim = ROWTYPE_part_dimen(rt,ptr,ii) ; /* dimension of part */
1104 if( dim > 0 && *apt != NULL ){
1105 NI_multival_to_text( rt->part_rtp[ii] , dim , *apt , outstr ) ;
1106 }
1107 }
1108 }
1109
1110 /* pare down the output string size */
1111
1112 ii = strlen(outstr) ;
1113 outstr = realloc( outstr , ii+1 ) ;
1114 return outstr ;
1115 }
1116
1117 /*------------------------------------------------------------------------*/
1118 /*! Remove an attribute, if it exists from a data or group element.
1119 ZSS Feb 09
1120 --------------------------------------------------------------------------*/
1121
NI_kill_attribute(void * nini,char * attname)1122 void NI_kill_attribute( void *nini , char *attname )
1123 {
1124 int nn , tt=NI_element_type(nini) ;
1125
1126 if( tt < 0 || attname == NULL || attname[0] == '\0' ) return ;
1127
1128 /* input is a data element */
1129
1130 if( tt == NI_ELEMENT_TYPE ){
1131 NI_element *nel = (NI_element *) nini ;
1132
1133 /* see if name is already in element header */
1134
1135 for( nn=0 ; nn < nel->attr_num ; nn++ )
1136 if( strcmp(nel->attr_lhs[nn],attname) == 0 ) break ;
1137
1138 if( nn == nel->attr_num ){ /* not found, return */
1139 return;
1140 } else {
1141 NI_free(nel->attr_lhs[nn]) ; /* free old attribute */
1142 NI_free(nel->attr_rhs[nn]) ;
1143 if ( nn < nel->attr_num-1 ) { /* move last attr to nn */
1144 nel->attr_lhs[nn] = nel->attr_lhs[nel->attr_num-1];
1145 nel->attr_lhs[nel->attr_num-1] = NULL;
1146 nel->attr_rhs[nn] = nel->attr_rhs[nel->attr_num-1];
1147 nel->attr_rhs[nel->attr_num-1] = NULL;
1148 }
1149 --nel->attr_num;
1150 /* reallocate */
1151 nel->attr_lhs = NI_realloc( nel->attr_lhs,
1152 char*, sizeof(char *)*(nel->attr_num) );
1153 nel->attr_rhs = NI_realloc( nel->attr_rhs,
1154 char*, sizeof(char *)*(nel->attr_num) );
1155 }
1156
1157 /* input is a group element */
1158
1159 } else if( tt == NI_GROUP_TYPE ){
1160 NI_group *ngr = (NI_group *) nini ;
1161
1162 for( nn=0 ; nn < ngr->attr_num ; nn++ )
1163 if( strcmp(ngr->attr_lhs[nn],attname) == 0 ) break ;
1164
1165 if( nn == ngr->attr_num ){
1166 return;
1167 } else {
1168 NI_free(ngr->attr_lhs[nn]) ;
1169 NI_free(ngr->attr_rhs[nn]) ;
1170 if ( nn < ngr->attr_num-1 ) { /* move last attr to nn */
1171 ngr->attr_lhs[nn] = ngr->attr_lhs[ngr->attr_num-1];
1172 ngr->attr_lhs[ngr->attr_num-1] = NULL;
1173 ngr->attr_rhs[nn] = ngr->attr_rhs[ngr->attr_num-1];
1174 ngr->attr_rhs[ngr->attr_num-1] = NULL;
1175 }
1176 --ngr->attr_num;
1177 /* reallocate */
1178 ngr->attr_lhs = NI_realloc( ngr->attr_lhs,
1179 char*, sizeof(char *)*(ngr->attr_num) );
1180 ngr->attr_rhs = NI_realloc( ngr->attr_rhs,
1181 char*, sizeof(char *)*(ngr->attr_num) );
1182 }
1183
1184 /* input is a processing instruction */
1185
1186 } else if( tt == NI_PROCINS_TYPE ){
1187 NI_procins *npi = (NI_procins *) nini ;
1188
1189 for( nn=0 ; nn < npi->attr_num ; nn++ )
1190 if( strcmp(npi->attr_lhs[nn],attname) == 0 ) break ;
1191
1192 if( nn == npi->attr_num ){
1193 return;
1194 } else {
1195 NI_free(npi->attr_lhs[nn]) ;
1196 NI_free(npi->attr_rhs[nn]) ;
1197 if ( nn < npi->attr_num-1 ) { /* move last attr to nn */
1198 npi->attr_lhs[nn] = npi->attr_lhs[npi->attr_num-1];
1199 npi->attr_lhs[npi->attr_num-1] = NULL;
1200 npi->attr_rhs[nn] = npi->attr_rhs[npi->attr_num-1];
1201 npi->attr_rhs[npi->attr_num-1] = NULL;
1202 }
1203 --npi->attr_num;
1204 /* reallocate */
1205 npi->attr_lhs = NI_realloc( npi->attr_lhs,
1206 char*, sizeof(char *)*(npi->attr_num) );
1207 npi->attr_rhs = NI_realloc( npi->attr_rhs,
1208 char*, sizeof(char *)*(npi->attr_num) );
1209 }
1210
1211 }
1212
1213 return ;
1214 }
1215
1216 /*------------------------------------------------------------------------*/
1217 /*! Add an attribute to a data or group element.
1218 If an attribute with the same attname already exists, then
1219 it will be replaced with this one.
1220 --------------------------------------------------------------------------*/
1221
NI_set_attribute(void * nini,char * attname,char * attvalue)1222 void NI_set_attribute( void *nini , char *attname , char *attvalue )
1223 {
1224 int nn , tt=NI_element_type(nini) ;
1225
1226 if( tt < 0 || attname == NULL || attname[0] == '\0' ) return ;
1227
1228 /* input is a data element */
1229
1230 if( tt == NI_ELEMENT_TYPE ){
1231 NI_element *nel = (NI_element *) nini ;
1232
1233 /* see if name is already in element header */
1234
1235 for( nn=0 ; nn < nel->attr_num ; nn++ )
1236 if( strcmp(nel->attr_lhs[nn],attname) == 0 ) break ;
1237
1238 /* if not, then add a header attribute */
1239
1240 if( nn == nel->attr_num ){
1241 nel->attr_lhs = NI_realloc( nel->attr_lhs, char*, sizeof(char *)*(nn+1) );
1242 nel->attr_rhs = NI_realloc( nel->attr_rhs, char*, sizeof(char *)*(nn+1) );
1243 nel->attr_num = nn+1 ;
1244 } else {
1245 NI_free(nel->attr_lhs[nn]) ; /* free old attribute */
1246 NI_free(nel->attr_rhs[nn]) ;
1247 }
1248
1249 nel->attr_lhs[nn] = NI_strdup(attname) ;
1250 nel->attr_rhs[nn] = NI_strdup(attvalue);
1251
1252 /* input is a group element */
1253
1254 } else if( tt == NI_GROUP_TYPE ){
1255 NI_group *ngr = (NI_group *) nini ;
1256
1257 for( nn=0 ; nn < ngr->attr_num ; nn++ )
1258 if( strcmp(ngr->attr_lhs[nn],attname) == 0 ) break ;
1259
1260 if( nn == ngr->attr_num ){
1261 ngr->attr_lhs = NI_realloc( ngr->attr_lhs, char*, sizeof(char *)*(nn+1) );
1262 ngr->attr_rhs = NI_realloc( ngr->attr_rhs, char*, sizeof(char *)*(nn+1) );
1263 ngr->attr_num = nn+1 ;
1264 } else {
1265 NI_free(ngr->attr_lhs[nn]) ;
1266 NI_free(ngr->attr_rhs[nn]) ;
1267 }
1268
1269 ngr->attr_lhs[nn] = NI_strdup(attname) ;
1270 ngr->attr_rhs[nn] = NI_strdup(attvalue);
1271
1272 /* input is a processing instruction */
1273
1274 } else if( tt == NI_PROCINS_TYPE ){
1275 NI_procins *npi = (NI_procins *) nini ;
1276
1277 for( nn=0 ; nn < npi->attr_num ; nn++ )
1278 if( strcmp(npi->attr_lhs[nn],attname) == 0 ) break ;
1279
1280 if( nn == npi->attr_num ){
1281 npi->attr_lhs = NI_realloc( npi->attr_lhs, char*, sizeof(char *)*(nn+1) );
1282 npi->attr_rhs = NI_realloc( npi->attr_rhs, char*, sizeof(char *)*(nn+1) );
1283 npi->attr_num = nn+1 ;
1284 } else {
1285 NI_free(npi->attr_lhs[nn]) ;
1286 NI_free(npi->attr_rhs[nn]) ;
1287 }
1288
1289 npi->attr_lhs[nn] = NI_strdup(attname) ;
1290 npi->attr_rhs[nn] = NI_strdup(attvalue);
1291 }
1292
1293 return ;
1294 }
1295
1296 /*------------------------------------------------------------------------*/
1297 /*! Copy all attributes from one element to the next.
1298 The function is not recursive and must have a target nel
1299 with no attributes. ZSS Oct 2010
1300 --------------------------------------------------------------------------*/
1301
NI_copy_all_attributes(void * nisrc,void * nitrg)1302 void NI_copy_all_attributes( void *nisrc , void *nitrg )
1303 {
1304 int nn , ttsrc=NI_element_type(nisrc), tttrg=NI_element_type(nitrg) ;
1305
1306 if( ttsrc < 0 || tttrg < 0 ) return ;
1307 if( tttrg != ttsrc) {
1308 fprintf(stderr,"Error NI_copy_all_attributes:\n"
1309 "Src and trg elements must have same type.\n");
1310 return;
1311 }
1312 /* input is a data element */
1313 if( ttsrc == NI_ELEMENT_TYPE ){
1314 NI_element *nelsrc = (NI_element *) nisrc ;
1315 NI_element *neltrg = (NI_element *) nitrg ;
1316 if( neltrg->attr_num != 0) {
1317 /* don't allow for this now. Else, you need to clear
1318 all pre-existing ones, or just common pre-existing ones
1319 then continue below */
1320 fprintf(stderr,"Error NI_copy_all_attributes:\n"
1321 "Must have no attributes in target element.\n");
1322 return;
1323 }
1324
1325 neltrg->attr_lhs = NI_realloc ( neltrg->attr_lhs,
1326 char*, sizeof(char *)*nelsrc->attr_num);
1327 neltrg->attr_rhs = NI_realloc ( neltrg->attr_rhs,
1328 char*, sizeof(char *)*nelsrc->attr_num);
1329 neltrg->attr_num = nelsrc->attr_num;
1330
1331 for( nn=0 ; nn < nelsrc->attr_num ; nn++ ) {
1332 neltrg->attr_lhs[nn] = NI_strdup(nelsrc->attr_lhs[nn]);
1333 neltrg->attr_rhs[nn] = NI_strdup(nelsrc->attr_rhs[nn]);
1334 }
1335
1336 /* input is a group element */
1337
1338 } else if( ttsrc == NI_GROUP_TYPE ){
1339 NI_group *ngrsrc = (NI_group *) nisrc ;
1340 NI_group *ngrtrg = (NI_group *) nitrg ;
1341 if( ngrtrg->attr_num != 0) {
1342 /* don't allow for this now. Else, you need to clear
1343 all pre-existing ones, or just common pre-existing ones
1344 then continue below */
1345 fprintf(stderr,"Error NI_copy_all_attributes:\n"
1346 "Must have no attributes in target element.\n");
1347 return;
1348 }
1349
1350 ngrtrg->attr_lhs = NI_realloc ( ngrtrg->attr_lhs,
1351 char*, sizeof(char *)*ngrsrc->attr_num);
1352 ngrtrg->attr_rhs = NI_realloc ( ngrtrg->attr_rhs,
1353 char*, sizeof(char *)*ngrsrc->attr_num);
1354 ngrtrg->attr_num = ngrsrc->attr_num;
1355
1356 for( nn=0 ; nn < ngrsrc->attr_num ; nn++ ) {
1357 ngrtrg->attr_lhs[nn] = NI_strdup(ngrsrc->attr_lhs[nn]);
1358 ngrtrg->attr_rhs[nn] = NI_strdup(ngrsrc->attr_rhs[nn]);
1359 }
1360
1361 /* input is a processing instruction */
1362
1363 } else if( ttsrc == NI_PROCINS_TYPE ){
1364 NI_procins *npisrc = (NI_procins *) nisrc ;
1365 NI_procins *npitrg = (NI_procins *) nitrg ;
1366 if( npitrg->attr_num != 0) {
1367 /* don't allow for this now. Else, you need to clear
1368 all pre-existing ones, or just common pre-existing ones
1369 then continue below */
1370 fprintf(stderr,"Error NI_copy_all_attributes:\n"
1371 "Must have no attributes in target element.\n");
1372 return;
1373 }
1374
1375 npitrg->attr_lhs = NI_realloc ( npitrg->attr_lhs,
1376 char*, sizeof(char *)*npisrc->attr_num);
1377 npitrg->attr_rhs = NI_realloc ( npitrg->attr_rhs,
1378 char*, sizeof(char *)*npisrc->attr_num);
1379 npitrg->attr_num = npisrc->attr_num;
1380
1381 for( nn=0 ; nn < npisrc->attr_num ; nn++ ) {
1382 npitrg->attr_lhs[nn] = NI_strdup(npisrc->attr_lhs[nn]);
1383 npitrg->attr_rhs[nn] = NI_strdup(npisrc->attr_rhs[nn]);
1384 }
1385 }
1386
1387 return ;
1388 }
1389
1390 /*------------------------------------------------------------------------*/
1391 /*! Duplicate a niml group or element.
1392 Function tested with test program niccc and -dup option ZSS Oct 2010
1393 --------------------------------------------------------------------------*/
1394
NI_duplicate(void * vel,byte with_data)1395 void *NI_duplicate(void *vel, byte with_data)
1396 {
1397 void *vdup=NULL;
1398 int tt=-1;
1399
1400 if (!vel) return(vdup);
1401 tt = NI_element_type(vel);
1402 if (tt == NI_ELEMENT_TYPE) {
1403 return(NI_duplicate_element(vel, with_data));
1404 } else if (tt == NI_GROUP_TYPE){
1405 return(NI_duplicate_group(vel, with_data));
1406 } else {
1407 fprintf(stderr,
1408 "Error NI_duplicate:\n"
1409 "Can only deal with elements on group types\n");
1410 return(NULL);
1411 }
1412 return(NULL);
1413 }
1414
1415 /*------------------------------------------------------------------------*/
1416 /*! Duplicate niml element only.
1417 Better use function NI_duplicate ZSS Oct 2010
1418 --------------------------------------------------------------------------*/
1419
NI_duplicate_element(void * vel,byte with_data)1420 void *NI_duplicate_element (void *vel, byte with_data)
1421 {
1422 NI_element *ndup = NULL;
1423 NI_element *nel = (NI_element *)vel;
1424 NI_group *gel = (NI_group *)vel;
1425 NI_group *gdup = NULL;
1426 int tt=-1, i=0;
1427 void *vdup=NULL;
1428
1429 if (!vel) return(vdup);
1430
1431 tt = NI_element_type(vel);
1432 if (tt != NI_ELEMENT_TYPE) {
1433 fprintf(stderr,
1434 "Error NI_duplicate_element:\n"
1435 "Can only deal with elements\n");
1436 return(vdup);
1437 }
1438
1439 ndup = NI_new_data_element(nel->name, nel->vec_len);
1440
1441 /* copy the attributes */
1442 NI_copy_all_attributes(nel, ndup);
1443
1444 if (with_data) {
1445 /* copy the columns */
1446 for (i=0; i<nel->vec_num; ++i) {
1447 NI_add_column(ndup, nel->vec_typ[i],(void *)nel->vec[i]);
1448 }
1449 }
1450
1451 if( nel->vec_lab != NULL && ndup->vec_num > 0 ){ /* 12 Sep 2018 */
1452 NI_set_attribute_from_veclab_array( ndup , nel->vec_lab ) ;
1453 }
1454
1455 if (tt == NI_ELEMENT_TYPE) return((void *)ndup);
1456 else return(vdup);
1457 }
1458
1459 /*------------------------------------------------------------------------*/
1460 /* Make a new element from a list of columns in the old element */
1461
NI_extract_columns(NI_element * nel,int nc,int * cc)1462 NI_element * NI_extract_columns( NI_element *nel , int nc , int *cc )
1463 {
1464 NI_element *vnel ; int ii , jj ;
1465
1466 if( NI_element_type(nel) != NI_ELEMENT_TYPE ) return(NULL) ;
1467 if( nc < 1 || cc == NULL ) return(NULL) ;
1468
1469 vnel = NI_new_data_element(nel->name, nel->vec_len);
1470
1471 NI_copy_all_attributes( nel, vnel ) ;
1472
1473 /* copy desired columns */
1474
1475 for( ii=0 ; ii < nc ; ii++ ){
1476 jj = cc[ii] ; if( jj < 0 || jj >= nel->vec_num ) continue ;
1477 NI_add_column( vnel , nel->vec_typ[jj] , (void *)nel->vec[jj] ) ;
1478 if( nel->vec_lab != NULL )
1479 NI_set_column_label( vnel , ii , nel->vec_lab[jj] ) ;
1480 }
1481
1482 return(vnel) ;
1483 }
1484
1485 /*------------------------------------------------------------------------*/
1486 /*! Duplicate niml group only.
1487 Better use function NI_duplicate ZSS Oct 2010
1488 --------------------------------------------------------------------------*/
1489
NI_duplicate_group(void * vel,byte with_data)1490 void *NI_duplicate_group (void *vel, byte with_data)
1491 {
1492 NI_group *gel = (NI_group *)vel;
1493 NI_group *gdup = NULL;
1494 void *vv=NULL;
1495 int tt=-1, i=0;
1496 void *vdup=NULL, *gg=NULL;
1497
1498 if (!vel) return(vdup);
1499
1500 tt = NI_element_type(vel);
1501 if (tt != NI_GROUP_TYPE) {
1502 fprintf(stderr,
1503 "Error NI_duplicate_group:\n"
1504 "Can only deal with groups in this function\n");
1505 return(vdup);
1506 }
1507
1508 gdup = NI_new_group_element();
1509 NI_rename_group(gdup, gel->name);
1510
1511 /* copy the attributes to gdup*/
1512 NI_copy_all_attributes(gel, gdup);
1513
1514 /* copy all the elements */
1515 for (i=0; i<gel->part_num; ++i) {
1516 switch( gel->part_typ[i] ){
1517 /*-- a sub-group ==> recursion! --*/
1518 case NI_GROUP_TYPE:
1519 if (!(gg = NI_duplicate_group(gel->part[i], with_data))) {
1520 fprintf(stderr,
1521 "Error NI_duplicate_group:\n"
1522 "Failed at recursion\n");
1523 return(NULL);
1524 }
1525 NI_add_to_group(gdup, gg);
1526 break ;
1527 case NI_ELEMENT_TYPE:
1528 if (!(gg = NI_duplicate_element(gel->part[i],with_data))) {
1529 fprintf(stderr,
1530 "Error NI_duplicate_element:\n"
1531 "Failed at recursion\n");
1532 return(NULL);
1533 }
1534 NI_add_to_group(gdup, gg);
1535 break;
1536 default:
1537 fprintf(stderr,
1538 "Error NI_duplicate_group:\n"
1539 "No duplication implemented for type %d, ignoring.\n",
1540 gel->part_typ[i]);
1541 break;
1542 }
1543 }
1544 return(gdup);
1545 }
1546
1547 /*-----------------------------------------------------------------------*/
1548 /*! Get an attribute with the given LHS name. Returns a pointer to the
1549 RHS field in the element if the attribute name is found; otherwise
1550 returns NULL. If the LHS is found, but the RHS is NULL, returns
1551 a pointer to an empty C string ("\0"). Do not free() the result
1552 from this function, since it points to the internal field
1553 of the element!
1554 -------------------------------------------------------------------------*/
1555
NI_get_attribute_generic(void * nini,char * attname,int (* STRcomp)(const char *,const char *))1556 char * NI_get_attribute_generic( void *nini , char *attname ,
1557 int (*STRcomp)(const char *, const char *) )
1558 {
1559 int nn , tt=NI_element_type(nini) ;
1560 static char *zorkon = "\0" ;
1561
1562 if( tt < 0 || attname == NULL || attname[0] == '\0' ) return NULL ;
1563
1564 /* input is a data element */
1565
1566 if( tt == NI_ELEMENT_TYPE ){
1567 NI_element *nel = (NI_element *) nini ;
1568
1569 for( nn=0 ; nn < nel->attr_num ; nn++ )
1570 if( STRcomp(nel->attr_lhs[nn],attname) == 0 ) break ;
1571
1572 if( nn == nel->attr_num ) return NULL ;
1573
1574 if( nel->attr_rhs[nn] == NULL ) return zorkon ;
1575
1576 return nel->attr_rhs[nn] ;
1577
1578 /* input is a group element */
1579
1580 } else if( tt == NI_GROUP_TYPE ){
1581 NI_group *ngr = (NI_group *) nini ;
1582
1583 for( nn=0 ; nn < ngr->attr_num ; nn++ )
1584 if( STRcomp(ngr->attr_lhs[nn],attname) == 0 ) break ;
1585
1586 if( nn == ngr->attr_num ) return NULL ;
1587
1588 if( ngr->attr_rhs[nn] == NULL ) return zorkon ;
1589
1590 return ngr->attr_rhs[nn] ;
1591
1592 /* input is a processing instruction */
1593
1594 } else if( tt == NI_PROCINS_TYPE ){
1595 NI_procins *npi = (NI_procins *) nini ;
1596
1597 for( nn=0 ; nn < npi->attr_num ; nn++ )
1598 if( STRcomp(npi->attr_lhs[nn],attname) == 0 ) break ;
1599
1600 if( nn == npi->attr_num ) return NULL ;
1601
1602 if( npi->attr_rhs[nn] == NULL ) return zorkon ;
1603
1604 return npi->attr_rhs[nn] ;
1605 }
1606
1607 return NULL ; /* should never be reached */
1608 }
1609
1610 /*-----------------------------------------------------------------------*/
1611 /* This stuff added 20 Aug 2019 [RWC] */
1612
NI_get_attribute(void * nini,char * attname)1613 char * NI_get_attribute( void *nini , char *attname )
1614 {
1615 return NI_get_attribute_generic( nini , attname, strcmp ) ;
1616 }
1617
NI_get_attribute_nocase(void * nini,char * attname)1618 char * NI_get_attribute_nocase( void *nini , char *attname )
1619 {
1620 return NI_get_attribute_generic( nini , attname, strcasecmp ) ;
1621 }
1622
1623 /*-----------------------------------------------------------------------*/
1624 /*! Set the dimen attribute for a data element.
1625 -------------------------------------------------------------------------*/
1626
NI_set_dimen(NI_element * nel,int rank,int * nd)1627 void NI_set_dimen( NI_element *nel , int rank , int *nd )
1628 {
1629 int ii , ntot ;
1630
1631 if( nel == NULL || nel->type != NI_ELEMENT_TYPE ||
1632 rank < 1 || nd == NULL ) return ; /* bad */
1633
1634 for( ntot=1,ii=0 ; ii < rank ; ii++ ){
1635 if( nd[ii] <= 0 ) return ; /* bad */
1636 ntot *= nd[ii] ;
1637 }
1638 if( ntot != nel->vec_len ) return ; /* bad */
1639
1640 nel->vec_rank = rank ;
1641 nel->vec_axis_len = NI_realloc( nel->vec_axis_len, int, sizeof(int)*rank ) ;
1642 memcpy( nel->vec_axis_len , nd , sizeof(int)*rank ) ;
1643 return ;
1644 }
1645
1646 /*-----------------------------------------------------------------------*/
1647 /*! Set the delta attribute for a data element.
1648 Do not call this function until NI_set_dimen() has been called,
1649 unless there is only 1 dimension (which is the default).
1650 -------------------------------------------------------------------------*/
1651
NI_set_delta(NI_element * nel,float * del)1652 void NI_set_delta( NI_element *nel , float *del )
1653 {
1654 if( nel == NULL || nel->type != NI_ELEMENT_TYPE ||
1655 nel->vec_rank < 1 || del == NULL ) return ;
1656
1657 nel->vec_axis_delta = NI_realloc( nel->vec_axis_delta , float,
1658 nel->vec_rank * sizeof(float) ) ;
1659 memcpy( nel->vec_axis_delta , del , nel->vec_rank * sizeof(float) ) ;
1660 return ;
1661 }
1662
1663 /*-----------------------------------------------------------------------*/
1664 /*! Set the origin attribute for a data element.
1665 Do not call this function until NI_set_dimen() has been called,
1666 unless there is only 1 dimension (which is the default).
1667 -------------------------------------------------------------------------*/
1668
NI_set_origin(NI_element * nel,float * org)1669 void NI_set_origin( NI_element *nel , float *org )
1670 {
1671 if( nel == NULL || nel->type != NI_ELEMENT_TYPE ||
1672 nel->vec_rank < 1 || org == NULL ) return ;
1673
1674 nel->vec_axis_origin = NI_realloc( nel->vec_axis_origin , float,
1675 nel->vec_rank * sizeof(float) ) ;
1676 memcpy( nel->vec_axis_origin , org , nel->vec_rank * sizeof(float) ) ;
1677 return ;
1678 }
1679
1680 /*-----------------------------------------------------------------------*/
1681 /*! Set the units attribute for a data element.
1682 Do not call this function until NI_set_dimen() has been called,
1683 unless there is only 1 dimension (which is the default).
1684 -------------------------------------------------------------------------*/
1685
NI_set_units(NI_element * nel,char ** units)1686 void NI_set_units( NI_element *nel , char **units )
1687 {
1688 int ii ;
1689
1690 if( nel == NULL || nel->type != NI_ELEMENT_TYPE ||
1691 nel->vec_rank < 1 || units == NULL ) return ;
1692
1693 nel->vec_axis_unit = NI_realloc( nel->vec_axis_unit , char*,
1694 nel->vec_rank * sizeof(char *) ) ;
1695 for( ii=0 ; ii < nel->vec_rank ; ii++ )
1696 nel->vec_axis_unit[ii] = NI_strdup( units[ii] ) ;
1697 return ;
1698 }
1699
1700 /*-----------------------------------------------------------------------*/
1701 /*! Set the axes attribute for a data element.
1702 Do not call this function until NI_set_dimen() has been called,
1703 unless there is only 1 dimension (which is the default).
1704 -------------------------------------------------------------------------*/
1705
NI_set_axes(NI_element * nel,char ** ax)1706 void NI_set_axes( NI_element *nel , char **ax )
1707 {
1708 int ii ;
1709
1710 if( nel == NULL || nel->type != NI_ELEMENT_TYPE ||
1711 nel->vec_rank < 1 || ax == NULL ) return ;
1712
1713 nel->vec_axis_label = NI_realloc( nel->vec_axis_label , char*,
1714 nel->vec_rank * sizeof(char *) ) ;
1715 for( ii=0 ; ii < nel->vec_rank ; ii++ )
1716 nel->vec_axis_label[ii] = NI_strdup( ax[ii] ) ;
1717 return ;
1718 }
1719
1720 /*-----------------------------------------------------------------------*/
1721 /*! Create a new processing instruction with a given 'target' name.
1722 -------------------------------------------------------------------------*/
1723
NI_new_processing_instruction(char * name)1724 NI_procins * NI_new_processing_instruction( char *name )
1725 {
1726 NI_procins *npi ;
1727
1728 if( name == NULL || name[0] == '\0' ) return NULL ;
1729
1730 npi = NI_malloc(NI_procins,sizeof(NI_procins)) ;
1731
1732 npi->type = NI_PROCINS_TYPE ;
1733 npi->name = NI_strdup(name) ;
1734
1735 npi->attr_num = 0 ;
1736 npi->attr_lhs = npi->attr_rhs = NULL ;
1737
1738 return npi ;
1739 }
1740
1741 /*-----------------------------------------------------------------------*/
1742 /*! Create a new group element.
1743 -------------------------------------------------------------------------*/
1744
NI_new_group_element(void)1745 NI_group * NI_new_group_element(void)
1746 {
1747 NI_group *ngr ;
1748
1749 ngr = NI_malloc(NI_group, sizeof(NI_group) ) ;
1750
1751 ngr->type = NI_GROUP_TYPE ;
1752
1753 ngr->outmode = -1 ; /* 29 Mar 2005 */
1754
1755 ngr->attr_num = 0 ;
1756 ngr->attr_lhs = ngr->attr_rhs = NULL ;
1757
1758 ngr->part_num = 0 ;
1759 ngr->part_typ = NULL ;
1760 ngr->part = NULL ;
1761 ngr->name = NULL ; /* 03 Jun 2002 */
1762 ngr->filename = NULL ; /* 16 Jun 2020 */
1763
1764 return ngr ;
1765 }
1766
1767 /*-----------------------------------------------------------------------*/
1768 /*! Add an element to a group element.
1769 -------------------------------------------------------------------------*/
1770
NI_add_to_group(NI_group * ngr,void * nini)1771 void NI_add_to_group( NI_group *ngr , void *nini )
1772 {
1773 int nn , tt=NI_element_type(nini) ;
1774
1775 if( ngr == NULL || ngr->type != NI_GROUP_TYPE || tt < 0 ) return ;
1776
1777 nn = ngr->part_num ;
1778
1779 ngr->part_typ = NI_realloc( ngr->part_typ , int, sizeof(int)*(nn+1) ) ;
1780 ngr->part_typ[nn] = tt ;
1781 ngr->part = NI_realloc( ngr->part , void*, sizeof(void *)*(nn+1) );
1782 ngr->part[nn] = nini ;
1783 ngr->part_num = nn+1 ;
1784 return ;
1785 }
1786
1787 /*-----------------------------------------------------------------------*/
1788 /*! Remove an element from a group. Does NOT delete the element;
1789 that is the caller's responsibility, if desired.
1790 -------------------------------------------------------------------------*/
1791
NI_remove_from_group(NI_group * ngr,void * nini)1792 void NI_remove_from_group( NI_group *ngr , void *nini ) /* 16 Apr 2005 */
1793 {
1794 int ii , nn , jj ;
1795
1796 if( ngr == NULL || ngr->type != NI_GROUP_TYPE || nini == NULL ) return ;
1797
1798 nn = ngr->part_num ;
1799 for( ii=0 ; ii < nn ; ii++ ) /* search for part */
1800 if( nini == ngr->part[ii] ) break ;
1801 if( ii == nn ) return ; /* not found */
1802
1803 for( jj=ii+1 ; jj < nn ; jj++ ){ /* move parts above down */
1804 ngr->part_typ[jj-1] = ngr->part_typ[jj] ;
1805 ngr->part [jj-1] = ngr->part [jj] ;
1806 }
1807 ngr->part[nn-1] = NULL ; /* NULL-ify last part to be safe */
1808 ngr->part_num -- ; /* reduce part count */
1809 return ;
1810 }
1811
1812 /*-----------------------------------------------------------------------*/
1813 /*! Rename a group element from the default - 03 Jun 2002.
1814 -------------------------------------------------------------------------*/
1815
NI_rename_group(NI_group * ngr,char * nam)1816 void NI_rename_group( NI_group *ngr , char *nam )
1817 {
1818 if( ngr == NULL || ngr->type != NI_GROUP_TYPE ) return ;
1819 NI_free( ngr->name ) ;
1820 ngr->name = NI_strdup(nam) ;
1821 return ;
1822 }
1823
1824 /*-----------------------------------------------------------------------*/
1825 /*! Return a list of all elements in a group that have a given name.
1826 - This is a 'shallow' search: if the group itself contains
1827 groups, these sub-groups are not searched.
1828 - Return value of function is number of elements found (might be 0).
1829 - If something is found, then *nipt is an array of 'void *', each
1830 of which points to a matching element.
1831 - The returned elements might be group or data elements.
1832 - Sample usage:
1833 - int n,i ; void **nelar ;
1834 - n = NI_search_group_shallow( ngr , "fred" , &nelar ) ;
1835 - for( i=0 ; i < n ; i++ ) do_something( nelar[ii] ) ;
1836 - if( n > 0 ) NI_free(nelar) ;
1837 -------------------------------------------------------------------------*/
1838
NI_search_group_shallow(NI_group * ngr,char * enam,void *** nipt)1839 int NI_search_group_shallow( NI_group *ngr , char *enam , void ***nipt )
1840 {
1841 void **nelar=NULL , *nini ;
1842 int ii , nn=0 ;
1843 char *nm ;
1844
1845 if( ngr == NULL || ngr->type != NI_GROUP_TYPE ) return 0 ;
1846 if( enam == NULL || *enam == '\0' || nipt == NULL ) return 0 ;
1847 if( ngr->part_num == 0 ) return 0 ;
1848
1849 for( ii=0 ; ii < ngr->part_num ; ii++ ){
1850 nini = ngr->part[ii] ;
1851 nm = NI_element_name( nini ) ;
1852 if( nm != NULL && strcmp(nm,enam) == 0 ){
1853 /* added *size 11 Jul 2006 [rickr] */
1854 nelar = (void **) NI_realloc(nelar,void*,(nn+1)*sizeof(void *)) ;
1855 nelar[nn++] = nini ;
1856 }
1857 }
1858
1859 if( nn > 0 ) *nipt = nelar ;
1860 return nn ;
1861 }
1862
1863 /*-----------------------------------------------------------------------*/
1864 /*! Return a list of all elements in a group that have a given name.
1865 - This is a 'deep' search: if the group itself contains
1866 groups, these sub-groups are searched, etc.
1867 - If a group element has the name 'enam' AND a data element within
1868 that group has the name 'enam' as well, they will BOTH be returned
1869 in this list.
1870 - Return value of function is number of elements found (might be 0).
1871 - If something is found, then *nipt is an array of 'void *', each
1872 of which points to a matching element.
1873 - The returned elements might be group or data elements.
1874 - Sample usage:
1875 - int n,i ; void **nelar ;
1876 - n = NI_search_group_shallow( ngr , "fred" , &nelar ) ;
1877 - for( i=0 ; i < n ; i++ ) do_something( nelar[ii] ) ;
1878 - if( n > 0 ) NI_free(nelar) ;
1879 -------------------------------------------------------------------------*/
1880
NI_search_group_deep(NI_group * ngr,char * enam,void *** nipt)1881 int NI_search_group_deep( NI_group *ngr , char *enam , void ***nipt )
1882 {
1883 void **nelar=NULL , *nini ;
1884 int ii , nn=0 ;
1885 char *nm ;
1886
1887 if( ngr == NULL || ngr->type != NI_GROUP_TYPE ) return 0 ;
1888 if( enam == NULL || *enam == '\0' || nipt == NULL ) return 0 ;
1889 if( ngr->part_num == 0 ) return 0 ;
1890
1891 for( ii=0 ; ii < ngr->part_num ; ii++ ){
1892 nini = ngr->part[ii] ;
1893 nm = NI_element_name( nini ) ;
1894 if( nm != NULL && strcmp(nm,enam) == 0 ){
1895 nelar = (void **) NI_realloc(nelar,void*,(nn+1)*sizeof(void *)) ;
1896 nelar[nn++] = nini ;
1897 }
1898 if( NI_element_type(nini) == NI_GROUP_TYPE ){ /* recursion */
1899 int nsub , jj ; void **esub ;
1900 nsub = NI_search_group_deep( nini , enam , &esub ) ;
1901 if( nsub > 0 ){
1902 nelar = (void **) NI_realloc(nelar,void*,(nn+nsub)*sizeof(void *)) ;
1903 for( jj=0 ; jj < nsub ; jj++ ) nelar[nn++] = esub[jj] ;
1904 NI_free(esub) ;
1905 }
1906 }
1907 }
1908
1909 if( nn > 0 ) *nipt = nelar ;
1910 return nn ;
1911 }
1912
1913 /*-----------------------------------------------------------------------*/
1914 /*! add a ni_type attribute to the element 14 Jul 2006 [rickr]
1915 (based on NI_write_element())
1916 -------------------------------------------------------------------------*/
NI_set_ni_type_atr(NI_element * nel)1917 void NI_set_ni_type_atr( NI_element * nel )
1918 {
1919 char * buf ; /* alloc in blocks of ~1K (bob noted names up to 255 chars) */
1920 char * posn ;
1921 int ii, prev, count=0 ;
1922 int req_len, total_len=1024 ;
1923
1924 if( ! nel || nel->vec_num <= 0 ) return ;
1925
1926 /* make enough space for a list of buffers, and init. to empty */
1927 /* -- NI_rowtype_define uses 255 as a max rowtype name length */
1928 buf = (char *)NI_malloc(char, total_len * sizeof(char)) ;
1929 buf[0] = '\0' ;
1930
1931 for( prev=-1, ii=0; ii < nel->vec_num; ii++ ){
1932 if( nel->vec_typ[ii] != prev ){ /* not the previous type */
1933 if( prev >= 0 ){ /* apply previous type now */
1934 posn = buf + strlen(buf);
1935 if( count > 1 ) sprintf(posn, "%d*%s,", count, NI_type_name(prev));
1936 else sprintf(posn, "%s,", NI_type_name(prev));
1937 }
1938 prev = nel->vec_typ[ii] ; /* save new type code */
1939 count = 1 ; /* have 1 such type */
1940
1941 /* make sure there is enough space for the new code */
1942 /* (old, new, and space for "5280*") 17 Jul 2006 [rickr] */
1943 req_len = strlen(buf) + strlen(NI_type_name(prev)) + 10 ;
1944 if( total_len < req_len )
1945 buf = (char *)NI_realloc(buf, char, (req_len+1024) * sizeof(char)) ;
1946
1947 } else { /* same as previous type */
1948 count++ ; /* so increment its count */
1949 }
1950 }
1951
1952 /* now write the last type found */
1953 posn = buf + strlen(buf) ;
1954 if( count > 1 ) sprintf(posn, "%d*%s", count, NI_type_name(prev));
1955 else sprintf(posn, "%s", NI_type_name(prev));
1956
1957 /* now add the string as an attribute, and nuke the old string */
1958 NI_set_attribute(nel, "ni_type", buf) ;
1959
1960 NI_free(buf) ;
1961
1962 return ;
1963 }
1964
1965 /*-----------------------------------------------------------------------*/
1966 /* Return a preview string for the top of a data element [22 Jun 2020].
1967 This string should be free()-ed after you are done with it.
1968 *//*---------------------------------------------------------------------*/
1969
NI_preview_string(NI_element * nel,int ntop,char * title)1970 char * NI_preview_string( NI_element *nel , int ntop , char *title )
1971 {
1972 int *cwid , csum , ii , jj , qq , nview , ncol ;
1973 char *qpt,*zpt , *vstring ;
1974
1975 if( NI_element_type(nel) != NI_ELEMENT_TYPE ) return NULL ;
1976
1977 ncol = nel->vec_num ; if( ncol <= 0 ) return NULL ;
1978 cwid = (int *)malloc(sizeof(int)*ncol) ; /* column width */
1979 if( ntop < 1 ) ntop = 1 ;
1980 nview = (ntop < nel->vec_len) ? ntop : nel->vec_len ;
1981
1982 /* scan for max width of each column */
1983
1984 NI_set_raw_val_to_text(1) ;
1985
1986 for( jj=0 ; jj < ncol ; jj++ ){ /* col #jj */
1987 cwid[jj] = 4 ;
1988 if( nel->vec_lab != NULL ){ /* col label */
1989 qq = NI_strlen(nel->vec_lab[jj]) ;
1990 if( qq > cwid[jj] ) cwid[jj] = qq ;
1991 }
1992 qpt = NI_rowtype_code_to_name( nel->vec_typ[jj] ) ; /* type name */
1993 qq = NI_strlen(qpt) ; /* do NOT free qpt! */
1994 if( qq > cwid[jj] ) cwid[jj] = qq ;
1995 for( ii=0 ; ii < nview ; ii++ ){ /* col values down the rows */
1996 qpt = NI_extract_text_value( nel , ii , jj ) ;
1997 qq = NI_strlen(qpt) ; free(qpt) ;
1998 if( qq > cwid[jj] ) cwid[jj] = qq ;
1999 }
2000 }
2001
2002 /* sum up all widths, create output string */
2003
2004 for( csum=jj=0 ; jj < ncol ; jj++ ) csum += cwid[jj]+2 ;
2005 if( title == NULL ) title = nel->filename ;
2006 jj = NI_strlen( title ) ;
2007 if( csum < jj+2 ) csum = jj+2 ;
2008
2009 vstring = (char *)calloc( sizeof(char), (nview+5)*(csum+1)+666 ) ;
2010
2011 if( jj > 0 ){
2012 jj = (csum-jj)/2 ; /* spacing to center title */
2013 sprintf( vstring , "%-*s%s\n" , jj , " " , title ) ;
2014 }
2015
2016 /* fill up output string */
2017 /* first row of printout = column labels (if any) */
2018
2019 for( jj=0 ; jj < ncol ; jj++ ){ /* col #jj */
2020 qpt = (nel->vec_lab != NULL ) ? nel->vec_lab[jj] : NULL ;
2021 if( qpt != NULL ){
2022 sprintf( vstring+strlen(vstring), " %-*s ", cwid[jj], qpt ) ;
2023 } else {
2024 char qstr[32] ;
2025 sprintf(qstr,"[%d]",jj) ;
2026 sprintf( vstring+strlen(vstring), " %-*s ", cwid[jj], qstr ) ;
2027 }
2028 }
2029 sprintf( vstring+strlen(vstring), "\n" ) ;
2030
2031 #if 0
2032 /* next row = column type labels (e.g., "float") */
2033
2034 for( jj=0 ; jj < ncol ; jj++ ){
2035 qpt = NI_rowtype_code_to_name( nel->vec_typ[jj] ) ;
2036 sprintf( vstring+strlen(vstring), " %-*s ", cwid[jj], qpt ) ;
2037 }
2038 sprintf( vstring+strlen(vstring), "\n" ) ;
2039 #endif
2040
2041 #if 1
2042 /* next row = underlining of column labels */
2043 #define DASHES "---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
2044 for( jj=0 ; jj < ncol ; jj++ ){
2045 sprintf( vstring+strlen(vstring) ,
2046 " %*.*s " , cwid[jj] , cwid[jj] , DASHES ) ;
2047 }
2048 sprintf( vstring+strlen(vstring), "\n" ) ;
2049 #endif
2050
2051 /* then do data rows */
2052
2053 for( ii=0 ; ii < nview ; ii++ ){
2054 for( jj=0 ; jj < ncol ; jj++ ){
2055 qpt = NI_extract_text_value( nel, ii, jj ) ;
2056 sprintf( vstring+strlen(vstring), " %-*s ", cwid[jj], qpt ) ;
2057 free(qpt) ; /* unlike the type labels, we free this string */
2058 }
2059 if( ii < nview-1 ) sprintf( vstring+strlen(vstring), "\n" ) ;
2060 }
2061
2062 NI_set_raw_val_to_text(0) ;
2063 free(cwid) ;
2064 return vstring ;
2065 }
2066