1 #include "mrilib.h"
2
3 #undef NLL
4 #define NLL 32766 /* lbuf length below -- should be enuf */
5
6 #undef LVEC
7 #define LVEC 666
8
9 #undef ERREX
10 #define ERREX(str) do{ ERROR_message(str); RETURN(NULL); } while(0)
11
12 #undef TRBUF
13 #define TRBUF(bb) \
14 do{ int lb=strlen(bb) ; if( bb[lb-1] == '\n' ) bb[lb-1] = '\0' ; } while(0)
15
16 /*** Modified 20-21 Jul 2011 to allow column selectors []
17 for the table. Column #0 must be the first one!
18 Row selectors {} don't really make sense, given that
19 the actual rows used are supposed to be taken using
20 column #0 as a key, and unselected rows are to be ignored. ***/
21
22 /*------------------------------------------------------------------------*/
23 /* Simple table: first column = labels, the rest are numbers. */
24
THD_simple_table_read(char * fname)25 NI_element * THD_simple_table_read( char *fname )
26 {
27 NI_str_array *sar ;
28 char *dname , *cpt , *dpt , *qpt , lbuf[NLL] ;
29 int ii,jj , ibot , nlab , row=0 , *ivlist=NULL , niv=0 ;
30 NI_element *nel ;
31 FILE *fts ;
32 float val ;
33 int verb = AFNI_yesenv("AFNI_DEBUG_TABLE") ;
34
35 ENTRY("THD_simple_table_read") ;
36
37 /*-- check for bad-ositiness --*/
38
39 if( fname == NULL || *fname == '\0' ) ERREX("Table: bad filename") ;
40 ii = strlen(fname) ;
41 if( (ii <= 2 && fname[0] == '-') ||
42 (ii <= 6 && strncmp(fname,"stdin" ,5) == 0) ||
43 (ii <= 9 && strncmp(fname,"/dev/fd0",8) == 0) ) ERREX("Table: stdin not allowed") ;
44 if( strncmp(fname,"1D:",3) == 0 ) ERREX("Table: 1D: not allowed") ;
45
46 /* copy filename to local variable for editing purposes */
47
48 dname = strdup(fname) ; if( dname[ii-1] == '\'' ) dname[ii-1] = '\0' ;
49
50 /*-- split filename and subvector list --*/
51
52 cpt = strstr(fname,"[") ; /* column list */
53 dpt = strstr(fname,"{") ; /* we don't use this row list */
54
55 if( cpt == fname || dpt == fname ){ /* can't be at start of filename! */
56 free(dname) ; ERREX("Table: '[ or {' selectors at start of filename") ;
57 } else { /* got a subvector list */
58 if( cpt != NULL ){ ii = cpt-fname; dname[ii] = '\0'; }
59 if( dpt != NULL ){ ii = dpt-fname; dname[ii] = '\0'; }
60 }
61
62 /* open input file */
63
64 if( verb ) INFO_message("Simple Table: processing file %s",dname) ;
65
66 fts = fopen(dname,"r") ; if( fts == NULL ){ free(dname); ERREX("Table: can't open file"); }
67
68 /* read lines until we get a useful line */
69
70 while(1){
71 lbuf[0] = '\0' ;
72 dpt = afni_fgets( lbuf , NLL , fts ) ; /* read a line of data */
73 if( dpt == NULL ){ fclose(fts); free(dname); ERREX("Table: can't read first line"); }
74 ii = strlen(lbuf) ; if( ii == 0 ) continue ; /* nada => loopback */
75 if( ii == 1 && isspace(lbuf[0]) ) continue ; /* 1 blank only => loopback */
76 ibot = (lbuf[0] == '#') ? 1 : 0 ; /* start of scanning */
77 for( ii=ibot ; isspace(lbuf[ii]) ; ii++ ) continue ; /* skip blanks */
78 if( lbuf[ii] == '\0' ) continue ; /* all blanks => loopback */
79 ibot = ii ; break ; /* can process this line */
80 }
81
82 TRBUF(lbuf) ;
83 if( verb ) ININFO_message(" first line = '%s'",lbuf+ibot) ;
84
85 /* break line into sub-strings */
86
87 sar = NI_decode_string_list( lbuf+ibot , ";" ) ;
88 if( sar == NULL ){ fclose(fts); free(dname); ERREX("Table: can't decode first line"); } /* nuthin? */
89
90 nlab = sar->num ;
91 if( verb ) ININFO_message(" found %d labels in first line",nlab) ;
92 if( nlab <= 1 ){
93 if( nlab == 1 ) /* need to have at least 2 columns! */
94 ERROR_message("Short table line (missing label or data?) -- %s",dname) ;
95 else
96 ERROR_message("No valid table line found in file %s",dname) ;
97 fclose(fts) ; NI_delete_str_array(sar) ; free(dname) ; RETURN(NULL) ;
98 }
99
100 /* 20 Jul 2011 -- get column list, if present */
101
102 if( cpt != NULL ){
103 if( verb ) ININFO_message(" processing column selector '%s'",cpt) ;
104 ivlist = MCW_get_intlist( nlab , cpt ) ;
105 if( ivlist != NULL ){
106 if( ivlist[0] <= 1 || ivlist[1] != 0 ){ /* must have col #0 first */
107 free(ivlist) ; ivlist=NULL ;
108 WARNING_message("Ignoring selector '%s' for table file '%s'",cpt,dname) ;
109 } else {
110 niv = ivlist[0] ; /* number of columns */
111 }
112 }
113 }
114
115 /* setup output data structure */
116
117 nel = NI_new_data_element( "AFNI_table" , LVEC ) ;
118
119 NI_add_column( nel , NI_STRING , NULL ) ;
120 if( niv <= 1 )
121 for( ii=1 ; ii < nlab ; ii++ ) NI_add_column( nel , NI_FLOAT , NULL ) ;
122 else
123 for( jj=2 ; jj <= niv ; jj++ ) NI_add_column( nel , NI_FLOAT , NULL ) ;
124
125 strcpy( lbuf , sar->str[0] ) ;
126 if( niv <= 1 ){
127 for( ii=1 ; ii < nlab ; ii++ ){
128 strcat( lbuf , ";" ) ; strcat( lbuf , sar->str[ii] ) ;
129 }
130 } else {
131 for( jj=2 ; jj <= niv ; jj++ ){
132 ii = ivlist[jj] ;
133 strcat( lbuf , ";" ) ; strcat( lbuf , sar->str[ii] ) ;
134 }
135 }
136 NI_set_attribute( nel , "Labels" , lbuf ) ;
137 NI_delete_str_array(sar) ;
138
139 /* now read lines and process them */
140
141 while(1){
142
143 /* scan ahead for next good input line */
144
145 while(1){
146 lbuf[0] = '\0' ; ibot = -1 ;
147 dpt = afni_fgets( lbuf , NLL , fts ) ; /* read a line of data */
148 if( dpt == NULL ) break ; /* error */
149 ii = strlen(lbuf) ; if( ii <= 2*nlab ) continue ; /* nada => loopback */
150 if( lbuf[0] == '#' ) continue ; /* comment => loopback */
151 ibot = (lbuf[0] == '#') ? 1 : 0 ; /* start of scanning */
152 for( ii=ibot ; isspace(lbuf[ii]) ; ii++ ) continue ; /* skip blanks */
153 if( lbuf[ii] == '\0' ) continue ; /* all blanks => loopback */
154 ibot = ii ; break ; /* can process this line */
155 } /* loop to get next line */
156
157 if( ibot < 0 ) break ; /* end of input ==> done with this file */
158
159 TRBUF(lbuf) ;
160 if( verb ) ININFO_message(" processing row #%d = '%s'",row,lbuf+ibot) ;
161
162 sar = NI_decode_string_list( lbuf+ibot , ";" ) ;
163 if( sar == NULL ) continue ; /* nuthin ==> loopback */
164
165 if( row >= nel->vec_len )
166 NI_alter_veclen( nel , nel->vec_len + LVEC ) ; /* need more data space */
167
168 /* put values from this line into this row of the table */
169
170 NI_insert_string( nel , row , 0 , sar->str[0] ) ; /* column #0 */
171 if( niv <= 1 ){ /* do all columns */
172 for( ii=1 ; ii < nlab ; ii++ ){
173 if( ii < sar->num ){
174 val = (float)strtod( sar->str[ii] , &qpt ) ;
175 if( *qpt != '\0' )
176 WARNING_message("value '%s' in table file '%s' row #%d col #%d is non-float",
177 sar->str[ii] , dname , row+1 , ii ) ;
178 } else {
179 val = 0.0f ;
180 WARNING_message("table file '%s' row #%d col #%d : no value present :-(",
181 dname , row+1 , ii ) ;
182 }
183 NI_insert_value( nel , row , ii , &val ) ;
184 }
185 } else { /* just some columns */
186 for( jj=2 ; jj <= niv ; jj++ ){
187 ii = ivlist[jj] ;
188 if( ii < sar->num ){
189 val = (float)strtod( sar->str[ii] , &qpt ) ;
190 if( *qpt != '\0' )
191 WARNING_message("value '%s' in table file '%s' row #%d col #%d is non-float",
192 sar->str[ii] , dname , row+1 , ii ) ;
193 } else {
194 val = 0.0f ;
195 WARNING_message("table file '%s' row #%d col #%d : no value present :-(",
196 dname , row+1 , ii ) ;
197 }
198 NI_insert_value( nel , row , jj-1 , &val ) ;
199 }
200 }
201
202 row++ ; /* have one more row! */
203 NI_delete_str_array(sar) ;
204
205 } /* loop to get next row */
206
207 /* cleanup and exit */
208
209 fclose(fts) ;
210 if( row == 0 ){ NI_free_element(nel); free(dname); ERREX("Table: no data lines found"); }
211 if( ivlist != NULL ) free(ivlist) ;
212
213 NI_alter_veclen(nel,row) ;
214
215 /* check for duplicate first column labels */
216
217 if( verb ) ININFO_message("checking for duplicate labels") ;
218
219 for( ii=0 ; ii < nel->vec_len ; ii++ ){
220 cpt = ((char **)(nel->vec[0]))[ii] ;
221 for( jj=ii+1 ; jj < nel->vec_len ; jj++ ){
222 dpt = ((char **)(nel->vec[0]))[jj] ;
223 if( strcmp(cpt,dpt) == 0 )
224 WARNING_message("Table file '%s': rows %d & %d have same label %s",
225 dname , ii+1,jj+1,cpt) ;
226 }
227 }
228
229 if( verb ){
230 ININFO_message("Table element follows::") ;
231 NI_write_element_tofile( "stdout:" , nel , NI_TEXT_MODE ) ;
232 }
233
234 free(dname) ; RETURN(nel) ;
235 }
236
237 /*------------------------------------------------------------------------*/
238
string_ectomy(char * src,char * bad)239 void string_ectomy( char *src , char *bad ) /* 20 Jun 2012 */
240 {
241 int nsrc , nbad , is , io , ib ;
242 char *out , ccc ;
243
244 if( src == NULL || bad == NULL || *src == '\0' || *bad == '\0' ) return ;
245
246 nsrc = strlen(src) ; out = calloc(sizeof(char),(nsrc+1)) ;
247 nbad = strlen(bad) ;
248
249 for( io=is=0 ; is < nsrc ; is++ ){
250 ccc = src[is] ;
251 if( (unsigned char)ccc == 194u &&
252 (unsigned char)src[is+1] == 160u ){ /* nonbreaking space */
253 out[io++] = ' ' ; is++ ; continue ; /* replaced by regular space */
254 }
255 if( !isprint(ccc) ) continue ; /* non-printable == skip */
256 for( ib=0 ; ib < nbad && bad[ib] != ccc ; ib++ ) ; /*nada*/
257 if( ib == nbad ) out[io++] = ccc ; /* if not in bad list, keep */
258 }
259
260 if( io < nsrc ){
261 #if 0
262 ININFO_message("Table reading: replaced string %s -with- %s",src,out) ;
263 #endif
264 strcpy(src,out) ;
265 }
266
267 free(out) ; return ;
268 }
269
270 /*------------------------------------------------------------------------*/
271 /* This table has column #0 as strings (labels), and remaining
272 columns are numbers or strings. Each column is 'pure' in type.
273 *//*----------------------------------------------------------------------*/
274
THD_mixed_table_read(char * fname)275 NI_element * THD_mixed_table_read( char *fname )
276 {
277 NI_str_array *sar ;
278 char *dname , *cpt , *dpt , *qpt , lbuf[NLL] ;
279 int ii,jj , ibot , nlab , row=0 , *ivlist=NULL , niv=0 ;
280 NI_element *nel ;
281 FILE *fts ;
282 float val ;
283 int verb = AFNI_yesenv("AFNI_DEBUG_TABLE") ;
284
285 ENTRY("THD_mixed_table_read") ;
286
287 /*-- check for bad-ositiness --*/
288
289 if( fname == NULL || *fname == '\0' ) ERREX("Table: bad filename") ;
290 ii = strlen(fname) ;
291 if( (ii <= 2 && fname[0] == '-') ||
292 (ii <= 6 && strncmp(fname,"stdin" ,5) == 0) ||
293 (ii <= 9 && strncmp(fname,"/dev/fd0",8) == 0) ) ERREX("Table: stdin not allowed") ;
294 if( strncmp(fname,"1D:",3) == 0 ) ERREX("Table: 1D: not allowed") ;
295
296 /* copy filename to local variable for editing purposes */
297
298 dname = strdup(fname) ; if( dname[ii-1] == '\'' ) dname[ii-1] = '\0' ;
299
300 /*-- split filename and subvector list --*/
301
302 cpt = strstr(fname,"[") ; /* column list */
303 dpt = strstr(fname,"{") ; /* we don't use this row list */
304
305 if( cpt == fname || dpt == fname ){ /* can't be at start of filename! */
306 free(dname) ; ERREX("Table: '[{' selector at start of filename") ;
307 } else { /* got a subvector list */
308 if( cpt != NULL ){ ii = cpt-fname; dname[ii] = '\0'; }
309 if( dpt != NULL ){ ii = dpt-fname; dname[ii] = '\0'; }
310 }
311
312 /* open input file */
313
314 if( verb ) INFO_message("Mixed Table: processing file %s",dname) ;
315
316 fts = fopen(dname,"r") ; if( fts == NULL ){ free(dname); ERREX("Table: can't open file"); }
317
318 /* read lines until we get a useful line */
319
320 while(1){
321 lbuf[0] = '\0' ;
322 dpt = afni_fgets( lbuf , NLL , fts ) ; /* read a line of data */
323 if( dpt == NULL ){ fclose(fts); free(dname); ERREX("Table: Can't read first line"); }
324 ii = strlen(lbuf) ; if( ii == 0 ) continue ; /* nada => loopback */
325 if( ii == 1 && isspace(lbuf[0]) ) continue ; /* 1 blank only => loopback */
326 ibot = (lbuf[0] == '#') ? 1 : 0 ; /* start of scanning */
327 for( ii=ibot ; isspace(lbuf[ii]) ; ii++ ) continue ; /* skip blanks */
328 if( lbuf[ii] == '\0' ) continue ; /* all blanks => loopback */
329 ibot = ii ; break ; /* can process this line */
330 }
331
332 TRBUF(lbuf) ;
333 if( verb ) ININFO_message(" first line = '%s'",lbuf+ibot) ;
334
335 /* break line into sub-strings */
336
337 sar = NI_decode_string_list( lbuf+ibot , ";" ) ;
338 if( sar == NULL ){ fclose(fts); free(dname); ERREX("Table: Can't decode first line"); } /* nuthin? */
339
340 nlab = sar->num ; /* number of labels = number of separate strings */
341 if( verb ) ININFO_message(" found %d labels in first line",nlab) ;
342 if( nlab <= 1 ){
343 if( nlab == 1 ) /* need to have at least 2 columns! */
344 ERROR_message("short table line (missing label or data?) -- %s",dname) ;
345 else
346 ERROR_message("no valid table line found in file %s",dname) ;
347 fclose(fts) ; NI_delete_str_array(sar) ; free(dname) ; RETURN(NULL) ;
348 }
349
350 /* 21 Jul 2011 -- get column list, if present */
351
352 if( cpt != NULL ){
353 if( verb ) ININFO_message(" processing column selector '%s'",cpt) ;
354 ivlist = MCW_get_intlist( nlab , cpt ) ;
355 if( ivlist != NULL ){
356 if( ivlist[0] <= 1 || ivlist[1] != 0 ){
357 free(ivlist) ; ivlist=NULL ;
358 WARNING_message("Ignoring selector '%s' for table file '%s'",cpt,dname) ;
359 } else {
360 niv = ivlist[0] ;
361 }
362 }
363 }
364
365 /* setup output data structure */
366
367 nel = NI_new_data_element( "AFNI_table" , LVEC ) ;
368
369 NI_add_column( nel , NI_STRING , NULL ) ;
370
371 strcpy( lbuf , sar->str[0] ) ;
372 if( niv <= 1 ){
373 for( ii=1 ; ii < nlab ; ii++ ){
374 strcat( lbuf , ";" ) ; strcat( lbuf , sar->str[ii] ) ;
375 }
376 } else {
377 for( jj=2 ; jj <= niv ; jj++ ){
378 ii = ivlist[jj] ;
379 strcat( lbuf , ";" ) ; strcat( lbuf , sar->str[ii] ) ;
380 }
381 }
382 NI_set_attribute( nel , "Labels" , lbuf ) ;
383 NI_delete_str_array(sar) ;
384
385 /* now read following lines and process them */
386
387 while(1){
388
389 /* scan ahead for next good input line */
390
391 while(1){
392 lbuf[0] = '\0' ; ibot = -1 ;
393 dpt = afni_fgets( lbuf , NLL , fts ) ; /* read a line of data */
394 if( dpt == NULL ) break ; /* error */
395 ii = strlen(lbuf) ; if( ii <= 2*nlab ) continue ; /* nada => loopback */
396 if( lbuf[0] == '#' ) continue ; /* comment => loopback */
397 ibot = (lbuf[0] == '#') ? 1 : 0 ; /* start of scanning */
398 for( ii=ibot ; isspace(lbuf[ii]) ; ii++ ) continue ; /* skip blanks */
399 if( lbuf[ii] == '\0' ) continue ; /* all blanks => loopback */
400 ibot = ii ; break ; /* can process this line */
401 } /* loop to get next line */
402
403 if( ibot < 0 ) break ; /* end of input ==> done with this file */
404
405 TRBUF(lbuf) ;
406 if( verb ) ININFO_message(" processing row #%d = '%s'",row,lbuf+ibot) ;
407
408 sar = NI_decode_string_list( lbuf+ibot , ";" ) ;
409 if( sar == NULL ) continue ; /* nuthin ==> loopback */
410
411 if( row == 0 ){ /* first row ==> figure out format */
412 if( sar->num < nlab ){
413 ERROR_message("First row of values in '%s' is too short!",dname) ;
414 NI_delete_str_array(sar) ; NI_free_element(nel) ; fclose(fts) ;
415 free(dname) ; RETURN(NULL) ;
416 }
417 if( niv <= 1 ){
418 if( verb ) ININFO_message(" deciding format of %d columns",nlab-1) ;
419 for( ii=1 ; ii < nlab ; ii++ ){
420 val = (float)strtod( sar->str[ii] , &qpt ) ;
421 if( *qpt == '\0' ){
422 NI_add_column( nel , NI_FLOAT , NULL ) ;
423 if( verb ) ININFO_message(" -- col#%d is numeric",ii) ;
424 } else {
425 NI_add_column( nel , NI_STRING , NULL ) ;
426 if( verb ) ININFO_message(" -- col#%d is string",ii) ;
427 }
428 }
429 } else {
430 if( verb ) ININFO_message(" deciding format of %d chosen columns",niv-1) ;
431 for( jj=2 ; jj <= niv ; jj++ ){
432 ii = ivlist[jj] ;
433 val = (float)strtod( sar->str[ii] , &qpt ) ;
434 if( *qpt == '\0' ){
435 NI_add_column( nel , NI_FLOAT , NULL ) ;
436 if( verb ) ININFO_message(" -- col#%d is numeric",ii) ;
437 } else {
438 NI_add_column( nel , NI_STRING , NULL ) ;
439 if( verb ) ININFO_message(" -- col#%d is string",ii) ;
440 }
441 }
442 }
443 } /* end of decoding format */
444
445 if( row >= nel->vec_len )
446 NI_alter_veclen( nel , nel->vec_len + LVEC ) ; /* need more data space */
447
448 /* put values from this line into this row of the table */
449
450 NI_insert_string( nel , row , 0 , sar->str[0] ) ;
451 if( niv <= 1 ){
452 for( ii=1 ; ii < nlab ; ii++ ){
453 if( nel->vec_typ[ii] == NI_FLOAT ){
454 if( ii < sar->num ){
455 val = (float)strtod( sar->str[ii] , &qpt ) ;
456 if( *qpt != '\0' )
457 WARNING_message("value '%s' in table file '%s' row #%d col #%d is non-float",
458 sar->str[ii] , dname , row+1 , ii ) ;
459 } else{
460 val = 0.0f ;
461 WARNING_message("table file '%s' row #%d col #%d : no value present :-(",
462 dname , row+1 , ii ) ;
463 }
464 NI_insert_value( nel , row , ii , &val ) ;
465 } else {
466 if( ii < sar->num ) dpt = sar->str[ii] ;
467 else dpt = "N/A" ;
468 string_ectomy( dpt , "\"'" ) ;
469 NI_insert_string( nel , row , ii , dpt ) ;
470 }
471 }
472 } else {
473 for( jj=2 ; jj <= niv ; jj++ ){
474 ii = ivlist[jj] ;
475 /* vec_typ[ii] here would likely mean that K final columns would be
476 lost in the case of K text columns (after label)
477 --> issue noted by Phoebe from Harvard 26 Jul 2012 [rickr] */
478 if( nel->vec_typ[jj-1] == NI_FLOAT ){
479 if( ii < sar->num ){
480 val = (float)strtod( sar->str[ii] , &qpt ) ;
481 if( *qpt != '\0' )
482 WARNING_message("value '%s' in table file '%s' row #%d col #%d is non-float",
483 sar->str[ii] , dname , row+1 , ii ) ;
484 } else{
485 val = 0.0f ;
486 WARNING_message("table file '%s' row #%d col #%d : no value present :-(",
487 dname , row+1 , ii ) ;
488 }
489 NI_insert_value( nel , row , jj-1 , &val ) ;
490 } else {
491 if( ii < sar->num ) dpt = sar->str[ii] ;
492 else dpt = "N/A" ;
493 string_ectomy( dpt , "\"'" ) ;
494 NI_insert_string( nel , row , jj-1 , dpt ) ;
495 }
496 }
497 }
498
499 row++ ; /* have one more row! */
500 NI_delete_str_array(sar) ;
501
502 } /* loop to get next row */
503
504 /* cleanup and exit */
505
506 fclose(fts) ;
507 if( ivlist != NULL ) free(ivlist) ;
508 if( row == 0 ){ NI_free_element(nel); free(dname); ERREX("Table: no data in file"); }
509
510 NI_alter_veclen(nel,row) ;
511
512 /* check for duplicate first column labels */
513
514 if( verb ) ININFO_message("checking for duplicate labels") ;
515
516 for( ii=0 ; ii < nel->vec_len ; ii++ ){
517 cpt = ((char **)(nel->vec[0]))[ii] ;
518 for( jj=ii+1 ; jj < nel->vec_len ; jj++ ){
519 dpt = ((char **)(nel->vec[0]))[jj] ;
520 if( strcmp(cpt,dpt) == 0 )
521 WARNING_message("Table file '%s': rows %d & %d have same label %s",
522 dname,ii+1,jj+1,cpt) ;
523 }
524 }
525
526 if( verb ){
527 ININFO_message("Table element follows::") ;
528 NI_write_element_tofile( "stdout:" , nel , NI_TEXT_MODE ) ;
529 }
530
531 free(dname) ; RETURN(nel) ;
532 }
533
534 /*------------------------------------------------------------------------*/
535 /* This table has only strings, and no header labels.
536 Bit flags:
537 1 = read as tsv (tab separated values)
538 2 = skip column selectors, if present
539 4 = read as csv (comma separated values)
540 If neither 1 nor 4 is set, then whitespace and/or ';' are separators.
541 If 1 and 4 are both set, the separator is determined from fname;
542 however, if the suffix isn't .tsv or .csv (case-insensitive),
543 then you are back in the case where neither 1 nor 4 is set :(
544 *//*----------------------------------------------------------------------*/
545
THD_string_table_read(char * fname,int flags)546 NI_element * THD_string_table_read( char *fname , int flags )
547 {
548 NI_str_array *sar ;
549 char *dname , *cpt , *dpt , *qpt , lbuf[NLL] ;
550 int ii,jj , ibot , ncol=0 , row=0 , *ivlist=NULL , niv=0 ;
551 NI_element *nel ;
552 FILE *fts ;
553 float val ;
554 int verb = AFNI_yesenv("AFNI_DEBUG_TABLE") ;
555 int do_tsv = (flags & 1) != 0 ;
556 int skip_sel = (flags & 2) != 0 ;
557 int do_csv = (flags & 4) != 0 ; /* 15 Apr 2019 */
558
559 ENTRY("THD_string_table_read") ;
560
561 /*-- check for bad-ositiness --*/
562
563 if( fname == NULL || *fname == '\0' ) ERREX("Table: bad filename") ;
564 ii = strlen(fname) ;
565 if( (ii <= 2 && fname[0] == '-') ||
566 (ii <= 6 && strncmp(fname,"stdin" ,5) == 0) ||
567 (ii <= 9 && strncmp(fname,"/dev/fd0",8) == 0) ) ERREX("Table: stdin not allowed") ;
568 if( strncmp(fname,"1D:",3) == 0 ) ERREX("Table: 1D: not allowed") ;
569
570 /* copy filename to local variable for editing purposes */
571
572 dname = strdup(fname) ; if( dname[ii-1] == '\'' ) dname[ii-1] = '\0' ;
573
574 /*-- split filename and subvector list --*/
575
576 cpt = strstr(fname,"[") ; /* column list */
577 dpt = strstr(fname,"{") ; /* we don't use this row list */
578
579 if( cpt == fname || dpt == fname ){ /* can't be at start of filename! */
580 free(dname) ; ERREX("Table: '[{' selector at start of filename") ;
581 } else { /* got a subvector list */
582 if( cpt != NULL ){ ii = cpt-fname; dname[ii] = '\0'; }
583 if( dpt != NULL ){ ii = dpt-fname; dname[ii] = '\0'; }
584 }
585
586 /* open input file */
587
588 if( verb ) INFO_message("String Table: processing file %s",dname) ;
589
590 fts = fopen(dname,"r") ; if( fts == NULL ){ free(dname); ERREX("Table: can't open file"); }
591
592 /* 21 Jul 2011 -- get column list, if present */
593
594 if( cpt != NULL && !skip_sel ){
595 if( verb ) ININFO_message(" processing column selector '%s'",cpt) ;
596 ivlist = MCW_get_intlist( 6666 , cpt ) ;
597 if( ivlist != NULL ){
598 if( ivlist[0] < 1 ){
599 free(ivlist) ; ivlist=NULL ;
600 WARNING_message("Ignoring selector '%s' for table file '%s'",cpt,dname) ;
601 } else {
602 niv = ivlist[0] ;
603 }
604 }
605 }
606
607 /* setup output data structure */
608
609 nel = NI_new_data_element( "AFNI_table" , LVEC ) ;
610
611 /* now read lines and process them */
612
613 while(1){
614
615 /* scan ahead for next good input line */
616
617 while(1){
618 lbuf[0] = '\0' ; ibot = -1 ;
619 dpt = afni_fgets( lbuf , NLL , fts ) ; /* read a line of data */
620 if( dpt == NULL ) break ; /* error */
621 ii = strlen(lbuf) ; if( ii == 0 ) continue ; /* nada => loopback */
622 if( lbuf[0] == '#' ) continue ; /* comment => loopback */
623 ibot = 0 ; /* start of scanning */
624 for( ii=ibot ; isspace(lbuf[ii]) ; ii++ ) continue ; /* skip blanks */
625 if( lbuf[ii] == '\0' ) continue ; /* all blanks => loopback */
626 ibot = ii ; break ; /* can process this line */
627 } /* loop to get next line */
628
629 if( ibot < 0 ) break ; /* end of input ==> done with this file */
630
631 TRBUF(lbuf) ;
632 if( verb ) ININFO_message(" processing row #%d = '%s'",row,lbuf+ibot) ;
633
634 if( do_tsv && do_csv ){ /* 12 Jun 2020 */
635 do_tsv = STRING_HAS_SUFFIX_CASE( dname , ".tsv" ) ;
636 do_csv = !do_tsv && STRING_HAS_SUFFIX_CASE( dname , ".csv" ) ;
637 }
638
639 if( do_tsv )
640 sar = NI_strict_decode_string_list( lbuf+ibot, "\t" ) ; /* 08 Feb 2018 */
641 else if( do_csv )
642 sar = NI_strict_decode_string_list( lbuf+ibot, "," ) ; /* 15 Apr 2019 */
643 else
644 sar = NI_decode_string_list( lbuf+ibot , ";" ) ;
645 if( sar == NULL ) continue ; /* nuthin ==> loopback */
646
647 if( row == 0 ){ /* first row ==> format element */
648 ncol = (niv <= 0) ? sar->num : niv ;
649 for( ii=1 ; ii <= ncol ; ii++ )
650 NI_add_column( nel , NI_STRING , NULL ) ;
651 }
652
653 if( row >= nel->vec_len )
654 NI_alter_veclen( nel , nel->vec_len + LVEC ) ; /* need more data space */
655
656 /* put values from this line into this row of the table */
657
658 if( niv <= 0 ){
659 for( ii=0 ; ii < ncol ; ii++ ){
660 if( ii < sar->num ) dpt = sar->str[ii] ;
661 else dpt = "N/A" ;
662 string_ectomy( dpt , "\"'" ) ;
663 NI_insert_string( nel , row , ii , dpt ) ;
664 }
665 } else {
666 for( jj=1 ; jj <= niv ; jj++ ){
667 ii = ivlist[jj] ;
668 if( ii < sar->num ) dpt = sar->str[ii] ;
669 else dpt = "N/A" ;
670 string_ectomy( dpt , "\"'" ) ;
671 NI_insert_string( nel , row , jj-1 , dpt ) ;
672 }
673 }
674
675 row++ ; /* have one more row! */
676 NI_delete_str_array(sar) ;
677
678 } /* loop to get next row */
679
680 /* cleanup and exit */
681
682 fclose(fts) ;
683 if( ivlist != NULL ) free(ivlist) ;
684 if( row == 0 ){ NI_free_element(nel); free(dname); ERREX("Table: no data in file"); }
685
686 NI_alter_veclen(nel,row) ;
687
688 if( verb ){
689 ININFO_message("Table element follows::") ;
690 NI_write_element_tofile( "stdout:" , nel , NI_TEXT_MODE ) ;
691 }
692
693 free(dname) ; RETURN(nel) ;
694 }
695
696 /*----------------------------------------------------------------------------*/
697 /* Read a tab-separated file, and convert to a NI_element with
698 vector labels (vec_lab) and with numeric columns where possible.
699 *//*--------------------------------------------------------------------------*/
700
THD_read_tsv(char * fname)701 NI_element * THD_read_tsv( char *fname )
702 {
703 NI_element *tnel , *fnel=NULL ;
704 int ii,jj , vnum,vlen , nbad ;
705 char **vec_lab , **cpt , *dpt ;
706
707 ENTRY("THD_read_tsv") ;
708
709 /* try to read as a table of strings */
710
711 tnel = THD_string_table_read( fname , 3 ) ;
712 if( tnel == NULL ) RETURN(NULL) ;
713
714 vnum = tnel->vec_num ; /* number of columns */
715 vlen = tnel->vec_len - 1 ; /* first row is labels */
716 if( vnum < 1 && vlen < 2 ) RETURN(NULL) ;
717
718 /* extract labels from first string of each column vector */
719
720 /* INFO_message("TSV data from %s - %d cols %d rows",fname,vnum,vlen) ; */
721 vec_lab = NI_malloc( char* , sizeof(char *)*vnum ) ;
722 for( ii=0 ; ii < vnum ; ii++ ){
723 cpt = (char **)tnel->vec[ii] ;
724 vec_lab[ii] = NI_strdup( cpt[0] ) ;
725 /* ININFO_message(" vec_lab[%d] = %s",ii,vec_lab[ii]) ; */
726 }
727
728 fnel = NI_new_data_element( "tsv" , vlen ) ;
729
730 #undef FBAD
731 #define FBAD(sss) \
732 ( strcasecmp ((sss),"N/A" ) == 0 || \
733 strncasecmp((sss),"NAN",3) == 0 || \
734 strncasecmp((sss),"INF",3) == 0 )
735
736 /* ININFO_message("---columns---") ; */
737 for( ii=0 ; ii < vnum ; ii++ ){
738 cpt = (char **)tnel->vec[ii] ;
739 jj = NI_count_numbers( vlen , cpt+1 ) ;
740 if( jj == vlen ){ /* pure numbers */
741 float *far = (float *)malloc(sizeof(float)*vlen) ;
742 for( jj=0 ; jj < vlen ; jj++ ){
743 far[jj] = (float)strtod(cpt[jj+1],NULL) ;
744 }
745 nbad = thd_floatscan( vlen , far ) ;
746
747 /* repair bad things [17 Oct 2018] */
748 { int ngood=0 ; float sgood=0.0f ;
749 for( jj=0 ; jj < vlen ; jj++ ){
750 if( !FBAD(cpt[jj+1]) ){ ngood++ ; sgood += far[jj]; }
751 }
752 if( ngood < vlen ){
753 if( ngood > 0 ) sgood /= ngood ;
754 for( jj=0 ; jj < vlen ; jj++ ){
755 if( FBAD(cpt[jj+1]) ) far[jj] = sgood ;
756 }
757 }
758 }
759
760 NI_add_column( fnel , NI_FLOAT , far ) ;
761 NI_set_column_label( fnel , ii , vec_lab[ii] ) ;
762 free(far) ;
763 /* ININFO_message(" column %s: floats with %d errors",vec_lab[ii],nbad) ; */
764 } else { /* strings */
765 NI_add_column( fnel , NI_STRING , cpt+1 ) ;
766 NI_set_column_label( fnel , ii , vec_lab[ii] ) ;
767 /* ININFO_message(" column %s: strings",vec_lab[ii]) ; */
768 }
769 }
770
771 NI_free_element(tnel) ; /* old stuff gets thrown out */
772
773 /* see if we have to deal with column selectors */
774
775 dpt = strstr(fname,"[") ;
776 if( dpt != NULL ){
777 int *ivlist ;
778 ivlist = MCW_get_labels_intlist( fnel->vec_lab , vnum , dpt ) ;
779 if( ivlist != NULL && ivlist[0] > 0 ){ /* extract subset of columns */
780 NI_element *qnel = NI_extract_columns( fnel , ivlist[0] , ivlist+1 ) ;
781 if( qnel != NULL ){ NI_free_element(fnel) ; fnel = qnel ; }
782 }
783 }
784
785 /* NI_write_element_tofile( "stderr:" , fnel , NI_TEXT_MODE ) ; */
786
787 #if 0 /* debug */
788 INFO_message("=========== tsv dump ==========") ;
789 THD_write_tsv( "stdout:" , fnel ) ;
790 INFO_message("===============================") ;
791 #endif
792
793 RETURN(fnel) ;
794 }
795
796 /*----------------------------------------------------------------------------*/
797
THD_write_tsv(char * fname,NI_element * nel)798 void THD_write_tsv( char *fname , NI_element *nel )
799 {
800 char ssep[2] ; int notfirst,ii,kk ;
801 FILE *fp ;
802
803 ENTRY("THD_write_tsv") ;
804
805 if( fname == NULL || NI_element_type(nel) != NI_ELEMENT_TYPE ) EXRETURN ;
806 if( nel->vec_lab == NULL || nel->vec_num == 0 ) EXRETURN ;
807
808 fp = fopen_maybe(fname) ; if( fp == NULL ) EXRETURN ;
809
810 #undef SET_SEPCHAR
811 #define SET_SEPCHAR do{ ssep[0] = ( (notfirst++) ? '\t' : '\0' ) ; } while(0)
812 ssep[1] = '\0' ;
813
814 /* header row */
815
816 for( notfirst=kk=0 ; kk < nel->vec_num ; kk++ ){
817 SET_SEPCHAR ;
818 fprintf(fp,"%s%s",ssep,nel->vec_lab[kk]) ;
819 }
820 fprintf(fp,"\n") ;
821
822 /* data rows */
823
824 for( ii=0 ; ii < nel->vec_len ; ii++ ){
825 for( notfirst=kk=0 ; kk < nel->vec_num ; kk++ ){
826 SET_SEPCHAR ;
827 if( nel->vec_typ[kk] == NI_FLOAT ){
828 float *far = (float *)nel->vec[kk] ;
829 fprintf(fp,"%s%g",ssep,far[ii]) ;
830 } else if( nel->vec_typ[kk] == NI_STRING ){
831 char **cpt = (char **)nel->vec[kk] ;
832 fprintf(fp,"%s%s" , ssep , (cpt[ii] != NULL) ? cpt[ii] : "(null)" ) ;
833 }
834 }
835 fprintf(fp,"\n") ;
836 }
837
838 fclose_maybe(fp) ;
839 EXRETURN ;
840 }
841
842 /*----------------------------------------------------------------------------*/
843
THD_set_tsv_column_labels(NI_element * fnel,char ** clab)844 void THD_set_tsv_column_labels( NI_element *fnel , char **clab )
845 {
846 int jj ;
847
848 ENTRY("THD_set_tsv_column_labels") ;
849
850 if( NI_element_type(fnel) != NI_ELEMENT_TYPE ||
851 fnel->vec_num == 0 ||
852 clab == NULL ) EXRETURN ;
853
854 for( jj=0 ; jj < fnel->vec_num ; jj++ )
855 NI_set_column_label( fnel , jj , clab[jj] ) ;
856
857 EXRETURN ;
858 }
859
860 /*----------------------------------------------------------------------------*/
861 /* convert 1D or 2D MRI_IMAGE to a TSV NI_element */
862
THD_mri_to_tsv_element(MRI_IMAGE * imin,char ** clab)863 NI_element * THD_mri_to_tsv_element( MRI_IMAGE *imin , char **clab )
864 {
865 MRI_IMAGE *qim ;
866 int nx,ny , jj ;
867 float *far ;
868 NI_element *fnel ;
869 char qlab[32] ;
870
871 ENTRY("THD_mri_to_tsv_element") ;
872
873 if( imin == NULL || imin->nz > 1 ) RETURN(NULL) ;
874
875 nx = imin->nx ; ny = imin->ny ;
876 if( nx < 1 || ny < 1 ) RETURN(NULL) ;
877
878 if( imin->kind != MRI_float ) qim = mri_to_float(imin) ;
879 else qim = imin ;
880
881 far = MRI_FLOAT_PTR(qim) ;
882
883 fnel = NI_new_data_element( "tsv" , nx ) ;
884
885 for( jj=0 ; jj < ny ; jj++ ){
886 NI_add_column( fnel , NI_FLOAT , far+jj*nx ) ;
887 if( clab != NULL ){
888 NI_set_column_label( fnel , jj , clab[jj] ) ;
889 } else {
890 sprintf(qlab,"Col#%d",jj) ;
891 NI_set_column_label( fnel , jj , qlab ) ;
892 }
893 }
894
895 if( qim != imin ) mri_free(qim) ;
896
897 RETURN(fnel) ;
898 }
899
900 /*----------------------------------------------------------------------------*/
901 /* Read a comma-separated file, and convert to a NI_element with
902 vector labels (vec_lab) and with numeric columns where possible.
903 *//*--------------------------------------------------------------------------*/
904
THD_read_csv(char * fname)905 NI_element * THD_read_csv( char *fname )
906 {
907 NI_element *tnel , *fnel=NULL ;
908 int ii,jj , vnum,vlen , nbad ;
909 char **vec_lab , **cpt , *dpt ;
910
911 ENTRY("THD_read_csv") ;
912
913 /* try to read as a table of strings */
914
915 tnel = THD_string_table_read( fname , 5 ) ;
916 if( tnel == NULL ) RETURN(NULL) ;
917
918 vnum = tnel->vec_num ; /* number of columns */
919 vlen = tnel->vec_len - 1 ; /* first row is labels */
920 if( vnum < 1 && vlen < 2 ) RETURN(NULL) ;
921
922 /* extract labels from first string of each column vector */
923
924 /* INFO_message("CSV data from %s - %d cols %d rows",fname,vnum,vlen) ; */
925 vec_lab = NI_malloc( char* , sizeof(char *)*vnum ) ;
926 for( ii=0 ; ii < vnum ; ii++ ){
927 cpt = (char **)tnel->vec[ii] ;
928 vec_lab[ii] = NI_strdup( cpt[0] ) ;
929 /* ININFO_message(" vec_lab[%d] = %s",ii,vec_lab[ii]) ; */
930 }
931
932 fnel = NI_new_data_element( "csv" , vlen ) ;
933
934 #undef FBAD
935 #define FBAD(sss) \
936 ( strcasecmp ((sss),"N/A" ) == 0 || \
937 strncasecmp((sss),"NAN",3) == 0 || \
938 strncasecmp((sss),"INF",3) == 0 )
939
940 /* ININFO_message("---columns---") ; */
941 for( ii=0 ; ii < vnum ; ii++ ){
942 cpt = (char **)tnel->vec[ii] ;
943 jj = NI_count_numbers( vlen , cpt+1 ) ;
944 if( jj == vlen ){ /* pure numbers */
945 float *far = (float *)malloc(sizeof(float)*vlen) ;
946 for( jj=0 ; jj < vlen ; jj++ ){
947 far[jj] = (float)strtod(cpt[jj+1],NULL) ;
948 }
949 nbad = thd_floatscan( vlen , far ) ;
950
951 /* repair bad things [17 Oct 2018] */
952 { int ngood=0 ; float sgood=0.0f ;
953 for( jj=0 ; jj < vlen ; jj++ ){
954 if( !FBAD(cpt[jj+1]) ){ ngood++ ; sgood += far[jj]; }
955 }
956 if( ngood < vlen ){
957 if( ngood > 0 ) sgood /= ngood ;
958 for( jj=0 ; jj < vlen ; jj++ ){
959 if( FBAD(cpt[jj+1]) ) far[jj] = sgood ;
960 }
961 }
962 }
963
964 NI_add_column( fnel , NI_FLOAT , far ) ;
965 NI_set_column_label( fnel , ii , vec_lab[ii] ) ;
966 free(far) ;
967 /* ININFO_message(" column %s: floats with %d errors",vec_lab[ii],nbad) ; */
968 } else { /* strings */
969 NI_add_column( fnel , NI_STRING , cpt+1 ) ;
970 NI_set_column_label( fnel , ii , vec_lab[ii] ) ;
971 /* ININFO_message(" column %s: strings",vec_lab[ii]) ; */
972 }
973 }
974
975 NI_free_element(tnel) ; /* old stuff gets thrown out */
976
977 /* see if we have to deal with column selectors */
978
979 dpt = strstr(fname,"[") ;
980 if( dpt != NULL ){
981 int *ivlist ;
982 ivlist = MCW_get_labels_intlist( fnel->vec_lab , vnum , dpt ) ;
983 if( ivlist != NULL && ivlist[0] > 0 ){ /* extract subset of columns */
984 NI_element *qnel = NI_extract_columns( fnel , ivlist[0] , ivlist+1 ) ;
985 if( qnel != NULL ){ NI_free_element(fnel) ; fnel = qnel ; }
986 }
987 }
988
989 /* NI_write_element_tofile( "stderr:" , fnel , NI_TEXT_MODE ) ; */
990
991 #if 0 /* debug */
992 INFO_message("=========== csv dump ==========") ;
993 THD_write_csv( "stdout:" , fnel ) ;
994 INFO_message("===============================") ;
995 #endif
996
997 RETURN(fnel) ;
998 }
999
1000 /*----------------------------------------------------------------------------*/
1001
THD_write_csv(char * fname,NI_element * nel)1002 void THD_write_csv( char *fname , NI_element *nel )
1003 {
1004 char ssep[2] ; int notfirst,ii,kk ;
1005 FILE *fp ;
1006
1007 ENTRY("THD_write_csv") ;
1008
1009 if( fname == NULL || NI_element_type(nel) != NI_ELEMENT_TYPE ) EXRETURN ;
1010 if( nel->vec_lab == NULL || nel->vec_num == 0 ) EXRETURN ;
1011
1012 fp = fopen_maybe(fname) ; if( fp == NULL ) EXRETURN ;
1013
1014 #undef SET_SEPCHAR
1015 #define SET_SEPCHAR do{ ssep[0] = ( (notfirst++) ? ',' : '\0' ) ; } while(0)
1016 ssep[1] = '\0' ;
1017
1018 /* header row */
1019
1020 for( notfirst=kk=0 ; kk < nel->vec_num ; kk++ ){
1021 SET_SEPCHAR ;
1022 fprintf(fp,"%s%s",ssep,nel->vec_lab[kk]) ;
1023 }
1024 fprintf(fp,"\n") ;
1025
1026 /* data rows */
1027
1028 for( ii=0 ; ii < nel->vec_len ; ii++ ){
1029 for( notfirst=kk=0 ; kk < nel->vec_num ; kk++ ){
1030 SET_SEPCHAR ;
1031 if( nel->vec_typ[kk] == NI_FLOAT ){
1032 float *far = (float *)nel->vec[kk] ;
1033 fprintf(fp,"%s%g",ssep,far[ii]) ;
1034 } else if( nel->vec_typ[kk] == NI_STRING ){
1035 char **cpt = (char **)nel->vec[kk] ;
1036 fprintf(fp,"%s%s" , ssep , (cpt[ii] != NULL) ? cpt[ii] : "(null)" ) ;
1037 }
1038 }
1039 fprintf(fp,"\n") ;
1040 }
1041
1042 fclose_maybe(fp) ;
1043 EXRETURN ;
1044 }
1045
1046 /*----------------------------------------------------------------------------*/
1047
THD_set_csv_column_labels(NI_element * fnel,char ** clab)1048 void THD_set_csv_column_labels( NI_element *fnel , char **clab )
1049 {
1050 int jj ;
1051
1052 ENTRY("THD_set_csv_column_labels") ;
1053
1054 if( NI_element_type(fnel) != NI_ELEMENT_TYPE ||
1055 fnel->vec_num == 0 ||
1056 clab == NULL ) EXRETURN ;
1057
1058 for( jj=0 ; jj < fnel->vec_num ; jj++ )
1059 NI_set_column_label( fnel , jj , clab[jj] ) ;
1060
1061 EXRETURN ;
1062 }
1063
1064 /*----------------------------------------------------------------------------*/
1065 /* convert 1D or 2D MRI_IMAGE to a CSV NI_element */
1066
THD_mri_to_csv_element(MRI_IMAGE * imin,char ** clab)1067 NI_element * THD_mri_to_csv_element( MRI_IMAGE *imin , char **clab )
1068 {
1069 MRI_IMAGE *qim ;
1070 int nx,ny , jj ;
1071 float *far ;
1072 NI_element *fnel ;
1073 char qlab[32] ;
1074
1075 ENTRY("THD_mri_to_csv_element") ;
1076
1077 if( imin == NULL || imin->nz > 1 ) RETURN(NULL) ;
1078
1079 nx = imin->nx ; ny = imin->ny ;
1080 if( nx < 1 || ny < 1 ) RETURN(NULL) ;
1081
1082 if( imin->kind != MRI_float ) qim = mri_to_float(imin) ;
1083 else qim = imin ;
1084
1085 far = MRI_FLOAT_PTR(qim) ;
1086
1087 fnel = NI_new_data_element( "csv" , nx ) ;
1088
1089 for( jj=0 ; jj < ny ; jj++ ){
1090 NI_add_column( fnel , NI_FLOAT , far+jj*nx ) ;
1091 if( clab != NULL ){
1092 NI_set_column_label( fnel , jj , clab[jj] ) ;
1093 } else {
1094 sprintf(qlab,"Col#%d",jj) ;
1095 NI_set_column_label( fnel , jj , qlab ) ;
1096 }
1097 }
1098
1099 if( qim != imin ) mri_free(qim) ;
1100
1101 RETURN(fnel) ;
1102 }
1103
1104 /*----------------------------------------------------------------------------*/
1105 /* convert NIML data element to an MRI_IMAGE;
1106 only numeric columns are included in the output;
1107 if none are found, NULL is returned.
1108 *//*--------------------------------------------------------------------------*/
1109
THD_niml_to_mri(NI_element * nel)1110 MRI_IMAGE * THD_niml_to_mri( NI_element *nel )
1111 {
1112 int ncol , *icol , ii,jj , nx ;
1113 MRI_IMAGE *outim=NULL ;
1114 float *outar , *far ;
1115 char *comlab=NULL ;
1116
1117 ENTRY("THD_niml_to_mri") ;
1118
1119 if( NI_element_type(nel) != NI_ELEMENT_TYPE ) RETURN(NULL) ;
1120 if( nel->vec_num < 1 || nel->vec_len < 1 ) RETURN(NULL) ;
1121
1122 /* find numeric columns */
1123
1124 icol = (int *)malloc(sizeof(int)*nel->vec_num) ;
1125 for( ncol=jj=0 ; jj < nel->vec_num ; jj++ ){
1126 if( NI_IS_NUMERIC_TYPE(nel->vec_typ[jj]) ) icol[ncol++] = jj ;
1127 }
1128 if( ncol == 0 ){ free(icol) ; RETURN(NULL) ; } /* nothing */
1129
1130 nx = nel->vec_len ;
1131 outim = mri_new( nx , ncol , MRI_float ) ;
1132 outar = MRI_FLOAT_PTR(outim) ;
1133 for( jj=0 ; jj < ncol ; jj++ ){
1134 far = outar + jj*nx ;
1135 for( ii=0 ; ii < nx ; ii++ )
1136 far[ii] = NI_extract_float_value(nel,ii,icol[jj]) ;
1137 /* extract label */
1138 if( nel->vec_lab != NULL ){
1139 char *ccc = nel->vec_lab[icol[jj]] ;
1140 if( ccc == NULL || *ccc == '\0' ) ccc = "Fred" ;
1141 if( comlab == NULL ){
1142 comlab = (char *)calloc(16,sizeof(char)) ;
1143 strcpy(comlab,"LABELS:\t") ;
1144 }
1145 comlab = (char *)realloc( comlab , sizeof(char)*(strlen(comlab)+strlen(ccc)+4) ) ;
1146 if( jj > 0 ) strcat(comlab,"\t") ;
1147 strcat(comlab,ccc) ;
1148 }
1149 }
1150
1151 free(icol) ;
1152 if( comlab != NULL ) outim->comments = comlab ;
1153 RETURN(outim) ;
1154 }
1155