1 /*****************************************************************************
2    Major portions of this software are copyrighted by the Medical College
3    of Wisconsin, 1994-2000, and are released under the Gnu General Public
4    License, Version 2.  See the file README.Copyright for details.
5 ******************************************************************************/
6 
7 #include "mrilib.h"
8 
9 /* prototypes */
10 
11 static int THD_setup_mastery( THD_3dim_dataset * , int * ) ;
12 static THD_3dim_dataset * THD_open_3dcalc( char * ) ;
13 
14 /*-----------------------------------------------------------------
15    11 Jan 1999: Open a dataset, allowing for possible mastering.
16    21 Feb 2001: Allow for <a..b> sub-ranging as well.
17    26 Jul 2004: Change THD_setup_mastery to return int.    [rickr]
18                 Add THD_copy_dset_subs() function.
19 -------------------------------------------------------------------*/
20 
THD_open_dataset(char * pathname)21 THD_3dim_dataset * THD_open_dataset( char *pathname )
22 {
23    THD_3dim_dataset *dset=NULL ;
24    char dname[THD_MAX_NAME+222]="\0" , *subv=NULL ;  /* 8 May 2007 */
25    char *cpt=NULL , *bpt=NULL ;
26    int  *ivlist=NULL ;
27    int    ii=-1, jj=-1, kk=-1;
28    float  bot=1.0 , top=0.0 ;
29    char *qname=NULL ;
30 
31 ENTRY("THD_open_dataset") ;
32 
33    /*-- sanity check --*/
34 
35    if( pathname == NULL            ||
36        (ii=strlen(pathname)) == 0  ||
37        pathname[ii-1]        == '/'  ) RETURN(NULL) ;
38 
39    /*-- [16 Mar 2016] jRandomDataset:nx,ny,nz,nt --*/
40 
41    if( strncasecmp(pathname,"jRandomDataset:",15) == 0 && isdigit(pathname[15]) ){
42      int nx=0,ny=0,nz=0,nt=0 ;
43      if( strchr(pathname+15,':') != NULL )
44        sscanf( pathname+15 , "%d:%d:%d:%d" , &nx,&ny,&nz,&nt ) ;
45      else
46        sscanf( pathname+15 , "%d,%d,%d,%d" , &nx,&ny,&nz,&nt ) ;
47      dset = jRandomDataset(nx,ny,nz,nt) ;
48      if( dset == NULL )
49        WARNING_message("can't decode %s",pathname) ;
50      else
51        THD_patch_brickim(dset) ;
52      RETURN(dset) ;
53    }
54 
55    /*-- [23 Mar 2001] perhaps get from across the Web --*/
56 
57    if( strncmp(pathname,"http://",7) == 0 ||
58        strncmp(pathname,"ftp://" ,6) == 0   ){
59 
60      dset = THD_fetch_dataset( pathname ) ;
61      if( ISVALID_DSET(dset) &&
62         !ISVALID_MAT44(dset->daxes->ijk_to_dicom) )  /* 15 Dec 2005 */
63        THD_daxes_to_mat44(dset->daxes) ;
64      THD_patch_brickim(dset) ;                       /* 20 Oct 2006 */
65      RETURN(dset) ;
66    }
67 
68    /*-- [17 Mar 2000] check if this is a 3dcalc() run --*/
69 
70    if( strncmp(pathname,"3dcalc(",7) == 0 ||
71        strncmp(pathname,"3dcalc ",7) == 0   ){
72      dset = THD_open_3dcalc( pathname ) ;
73      if( ISVALID_DSET(dset) &&
74         !ISVALID_MAT44(dset->daxes->ijk_to_dicom) )  /* 15 Dec 2005 */
75        THD_daxes_to_mat44(dset->daxes) ;
76      THD_patch_brickim(dset) ;                       /* 20 Oct 2006 */
77      RETURN(dset) ;
78    }
79 
80    /*-- allow filelist:FILENAME to work like tcat       23 Jul 2012 [rickr] */
81    if( ! strncmp(pathname,"filelist:",9) ) {
82      dset = THD_open_tcat( pathname ) ;
83      if( ISVALID_DSET(dset) &&
84         !ISVALID_MAT44(dset->daxes->ijk_to_dicom) )  /* 15 Dec 2005 */
85        THD_daxes_to_mat44(dset->daxes) ;
86      THD_patch_brickim(dset);
87      RETURN(dset) ;
88    }
89 
90    /*-- [04 Aug 2004] allow input of a list of datasets, separated by spaces --*/
91    /*  unless a count command is used inside the brackets 9 May 2007 drg*/
92    /* allow use of spaces with AFNI_PATH_SPACES_OK        2 May 2012 [rickr]  */
93    if( ! AFNI_yesenv("AFNI_PATH_SPACES_OK") &&
94          (strchr(pathname,' ') != NULL )    &&
95          (strstr(pathname,"[count ")==NULL) &&
96          (strstr(pathname,"[1dcat ")==NULL) ) {
97      dset = THD_open_tcat( pathname ) ;
98      if( ISVALID_DSET(dset) &&
99         !ISVALID_MAT44(dset->daxes->ijk_to_dicom) )  /* 15 Dec 2005 */
100        THD_daxes_to_mat44(dset->daxes) ;
101      THD_patch_brickim(dset);
102      RETURN(dset) ;
103    }
104 
105    /*-- 7 Apr 2016 [rickr]: allow wildcards --*/
106    if( HAS_WILDCARD(pathname) ) {
107      dset = THD_open_tcat( pathname ) ;
108      if( ISVALID_DSET(dset) && !ISVALID_MAT44(dset->daxes->ijk_to_dicom) )
109         THD_daxes_to_mat44(dset->daxes) ;
110      THD_patch_brickim(dset);
111      RETURN(dset) ;
112    }
113 
114    /*-- expand "~/" to home directory [13 Feb 2008] (from here, must free qname if it was used) --*/
115 
116    if( pathname[0] == '~' && pathname[1] == '/' ){
117      char *eee = getenv("HOME") ;
118      if( eee != NULL ){
119        qname = (char *)malloc(sizeof(char)*(strlen(pathname)+strlen(eee)+222));
120        strcpy(qname,eee); strcat(qname,pathname+1);
121        pathname = qname ;
122      }
123    }
124 
125    /*-- [18 Oct 2016] check if input filename is super long --*/
126 
127    if( (ii=strlen(pathname)) >= THD_MAX_NAME ){  /* super long */
128      static int first=1 ;
129      ERROR_message("The following dataset filename is too long for AFNI:\n"
130                    "   %s\n** Length(filename)=%d --> The dataset above WILL NOT BE OPENED :((",
131                    pathname , ii ) ;
132      if( first ){
133        ERROR_message("(The longest filename allowed in AFNI is %d characters)",THD_MAX_NAME-1) ;
134        first = 0 ;
135      }
136      if( qname != NULL ) free(qname) ;
137      RETURN(NULL) ;
138    } else if( ii > THD_MAX_NAME/2 ){       /* just pretty long */
139      static int first=1 ;
140      WARNING_message("The following dataset filename is very long and might cause troubles:\n"
141                      "  %s\n * Length(filename)=%d !!" ,
142                      pathname , ii ) ;
143      if( first ){
144        WARNING_message("(The longest filename allowed in AFNI is %d characters)",THD_MAX_NAME-1) ;
145        first = 0 ;
146      }
147    }
148 
149    /*-- 04 Mar 2003: allow input of .1D files, which deals with [] itself --*/
150    /*-- 19 May 2012: [rickr] moved after spaces check (allow space cat)   --*/
151    /*-- 18 Dec 2019: [rickr] tried, but cannot simply check suffix, as
152                      there might be a single quote at the end or similar
153                      - let this whine if .1D is the middle of a name?     --*/
154 
155    if( strstr(pathname,".1D") != NULL || strncmp(pathname,"1D:",3) == 0 ){
156      dset = THD_open_1D( pathname ) ;
157      if( ISVALID_DSET(dset) &&
158         !ISVALID_MAT44(dset->daxes->ijk_to_dicom) )  /* 15 Dec 2005 */
159        THD_daxes_to_mat44(dset->daxes) ;
160      if( dset != NULL ){ THD_patch_brickim(dset); if(qname!=NULL)free(qname); RETURN(dset); }
161    }
162 
163    /*-- find the opening "[" and/or "<" --*/
164 
165    cpt = strstr(pathname,"[") ;
166    bpt = strstr(pathname,"<") ;  /* 21 Feb 2001 */
167    if( cpt == NULL && bpt == NULL ){            /* no "[" or "<"  */
168      dset = THD_open_one_dataset( pathname ) ;  /* ==> open      */
169      if( ISVALID_DSET(dset) &&
170         !ISVALID_MAT44(dset->daxes->ijk_to_dicom) )  /* 15 Dec 2005 */
171        THD_daxes_to_mat44(dset->daxes) ;
172      THD_patch_brickim(dset); if(qname!=NULL)free(qname); RETURN(dset);     /*     normally */
173    }
174 
175    if( cpt == pathname || bpt == pathname ){
176      if(qname!=NULL)free(qname); RETURN(NULL);  /* error */
177    }
178 
179    /* copy dataset filename to dname and selector string to subv */
180 
181    ii = (cpt != NULL ) ? cpt - pathname : 999999 ;
182    jj = (bpt != NULL ) ? bpt - pathname : 999999 ;
183    kk = MIN(ii,jj) ;
184    memcpy(dname,pathname,kk) ; dname[kk] = '\0' ;
185 
186    /* allow NIfTI extensions here                14 Apr 2006 [rickr] */
187    if( STRING_HAS_SUFFIX(dname,".mnc")    ||
188        STRING_HAS_SUFFIX(dname,".mri")    ||
189        STRING_HAS_SUFFIX(dname,".svl")      ){
190      ERROR_message("Can't use selectors on dataset: %s",pathname) ;
191      if(qname!=NULL)free(qname); RETURN(NULL) ;
192    }
193 
194    /* open the dataset */
195    dset = THD_open_one_dataset( dname ) ;
196    if( dset == NULL ){
197      if(qname!=NULL)free(qname); RETURN(NULL) ;
198    }
199 
200    /* parse the sub-brick selector string (if any) */
201 
202    if( cpt != NULL ){
203      char *qpt ;
204      subv = strdup(cpt);
205      /* strcpy(subv,cpt) ;  don't assume length   8 May 2007 [rickr,dglen] */
206      qpt = strstr(subv,"<") ; if( qpt != NULL ) *qpt = '\0' ;
207      ivlist =  MCW_get_thd_intlist( dset , subv ); /* ZSS Dec 09 */
208      free(subv) ;
209    }
210    if( ivlist == NULL ){
211      if( cpt != NULL ) {/* ZSS  Dec 09 */
212        /* The condition used to issue a warning and proceed.
213           Now it fails. */
214        ERROR_message("bad sub-brick selector %s", cpt);
215        if(qname!=NULL)free(qname); RETURN(NULL) ;
216      }
217      ivlist = (int *) malloc(sizeof(int)*(DSET_NVALS(dset)+1)) ;
218      ivlist[0] = DSET_NVALS(dset) ;
219      for( kk=0 ; kk < ivlist[0] ; kk++ ) ivlist[kk+1] = kk ;
220    }
221 
222    /* ************************************************ */
223    /* 21 Feb 2001: if present, load the sub-range data */
224 
225    /* THD_init_one_datablock() was not called   14 Apr 2006 [rickr] */
226    if( STRING_HAS_SUFFIX(dname,".hdr") || STRING_HAS_SUFFIX(dname,".nia")    ||
227        STRING_HAS_SUFFIX(dname,".nii") || STRING_HAS_SUFFIX(dname,".nii.gz") ||
228        STRING_HAS_SUFFIX(dname,".niml.dset")                                 ||
229        STRING_HAS_SUFFIX(dname,".gii") || STRING_HAS_SUFFIX(dname,".gii.dset")){
230       dset->dblk->master_bot = 1.0 ;
231       dset->dblk->master_top = 0.0 ;
232    }
233 
234    /* - moved to new function that goes after labels   17 Apr 2012 [rickr] */
235    /* - set single value, float .. range, or comma-delimited int list      */
236    /* - fail on illegal angle selector                                     */
237    if( bpt != NULL ) {
238       if( thd_check_angle_selector(dset, bpt) ) {
239          ERROR_message("bad angle bracket selector: %s", bpt);
240          RETURN(NULL);
241       }
242    }
243 
244    /* modify the dataset according to the selector string */
245 
246    THD_setup_mastery( dset , ivlist ) ;
247    free(ivlist) ;
248 
249    if( ISVALID_DSET(dset) &&
250       !ISVALID_MAT44(dset->daxes->ijk_to_dicom) )  /* 15 Dec 2005 */
251      THD_daxes_to_mat44(dset->daxes) ;
252 
253    THD_patch_brickim(dset); if(qname!=NULL)free(qname);
254    RETURN(dset);
255 }
256 
257 /*-----------------------------------------------------------------
258    Set up a dataset for being mastered; that is, reading only
259    a subset of sub-bricks from the master .BRIK file.
260 -------------------------------------------------------------------*/
261 
THD_setup_mastery(THD_3dim_dataset * dset,int * ivlist)262 static int THD_setup_mastery( THD_3dim_dataset *dset , int *ivlist )
263 {
264    int ibr , old_nvals , new_nvals ;
265    THD_datablock *dblk ;
266    int *btype , *ivl ;
267 
268    float   *old_brick_fac  ;
269    int64_t *old_brick_bytes ;
270    char   **old_brick_lab  ;
271    char   **old_brick_keywords ;
272    int     *old_brick_statcode ;
273    float  **old_brick_stataux ;
274    floatvec **old_brick_fdrcurve ;  /* 23 Jan 2008 */
275    floatvec **old_brick_mdfcurve ;  /* 22 Oct 2008 */
276 
277 ENTRY("THD_setup_mastery") ;
278 
279    /** sanity checks **/
280 
281    if( ! ISVALID_DSET(dset) || ivlist == NULL || ivlist[0] <= 0 ) RETURN(1) ;
282 
283    new_nvals = ivlist[0] ;
284    ivl       = ivlist + 1 ;
285    dblk      = dset->dblk ;
286    old_nvals = dblk->nvals ;
287 
288    ibr = THD_count_databricks(dblk) ; if( ibr > 0 ) RETURN(2) ;
289 
290    for( ibr=0 ; ibr < new_nvals ; ibr++ )
291       if( ivl[ibr] < 0 || ivl[ibr] >= old_nvals ) RETURN(3) ;
292 
293    /** save pointers to old datablock stuff **/
294 
295    old_brick_fac      = dblk->brick_fac      ; dblk->brick_fac      = NULL ;
296    old_brick_bytes    = dblk->brick_bytes    ; dblk->brick_bytes    = NULL ;
297    old_brick_lab      = dblk->brick_lab      ; dblk->brick_lab      = NULL ;
298    old_brick_keywords = dblk->brick_keywords ; dblk->brick_keywords = NULL ;
299    old_brick_statcode = dblk->brick_statcode ; dblk->brick_statcode = NULL ;
300    old_brick_stataux  = dblk->brick_stataux  ; dblk->brick_stataux  = NULL ;
301    old_brick_fdrcurve = dblk->brick_fdrcurve ; dblk->brick_fdrcurve = NULL ;
302    old_brick_mdfcurve = dblk->brick_mdfcurve ; dblk->brick_mdfcurve = NULL ;
303 
304    /** setup new dataset brick structure **/
305 
306    dblk->diskptr->nvals = dblk->nvals = new_nvals ;
307    dblk->malloc_type = DATABLOCK_MEM_MALLOC ;
308 
309    if( dset->taxis != NULL ){                /* must fix time axis */
310       if( new_nvals == 1 ){                  /* no time dependence */
311          myRwcFree( dset->taxis->toff_sl ) ;
312          myRwcFree( dset->taxis ) ;
313       } else {                               /* different number of times */
314          dset->taxis->ntt = new_nvals ;
315       }
316    } else {                                  /* 21 Feb 2001: change to bucket type */
317 
318       if( ISANAT(dset) && !ISANATBUCKET(dset) )
319          EDIT_dset_items( dset , ADN_func_type,ANAT_BUCK_TYPE , ADN_none ) ;
320       else if( ISFUNC(dset) && !ISFUNCBUCKET(dset) )
321          EDIT_dset_items( dset , ADN_func_type,FUNC_BUCK_TYPE , ADN_none ) ;
322 
323    }
324 
325    /* redo brick_fac */
326 
327    dblk->brick_fac = (float *) RwcMalloc( sizeof(float) * new_nvals ) ;
328    for( ibr=0 ; ibr < new_nvals ; ibr++ )
329       dblk->brick_fac[ibr] = old_brick_fac[ivl[ibr]] ;
330 
331    /* redo brick and brick_bytes */
332 
333    btype = (int *) malloc( sizeof(int) * new_nvals ) ;
334    for( ibr=0 ; ibr < new_nvals ; ibr++ )
335       btype[ibr] = DBLK_BRICK_TYPE(dblk,ivl[ibr]) ;
336    THD_init_datablock_brick( dblk , new_nvals , btype ) ;
337    free(btype) ;
338 
339    /* redo brick_lab */
340 
341    if( old_brick_lab != NULL ){
342      for( ibr=0 ; ibr < new_nvals ; ibr++ )
343        THD_store_datablock_label( dblk , ibr , old_brick_lab[ivl[ibr]] ) ;
344    }
345 
346    /* redo brick_keywords */
347 
348    if( old_brick_keywords != NULL ){
349      for( ibr=0 ; ibr < new_nvals ; ibr++ )
350        THD_store_datablock_keywords( dblk , ibr , old_brick_keywords[ivl[ibr]] ) ;
351    }
352 
353    /* redo brick_statcode and brick_stataux */
354 
355    if( old_brick_statcode != NULL ){
356       for( ibr=0 ; ibr < new_nvals ; ibr++ )
357          THD_store_datablock_stataux( dblk, ibr, old_brick_statcode[ivl[ibr]] ,
358                                            999 , old_brick_stataux [ivl[ibr]]  ) ;
359    }
360 
361    /* redo brick_fdrcurve now */
362 
363    if( old_brick_fdrcurve != NULL ){  /* 23 Jan 2008 */
364      floatvec *fv , *nv ;
365      dblk->brick_fdrcurve = (floatvec **)calloc(sizeof(floatvec *),new_nvals) ;
366      for( ibr=0 ; ibr < new_nvals ; ibr++ ){
367        fv = old_brick_fdrcurve[ivl[ibr]] ;
368        if( fv == NULL ){ nv = NULL; } else { COPY_floatvec(nv,fv); }
369        dblk->brick_fdrcurve[ibr] = nv ;
370      }
371    }
372 
373    if( old_brick_mdfcurve != NULL ){  /* 22 Oct 2008 */
374      floatvec *fv , *nv ;
375      dblk->brick_mdfcurve = (floatvec **)calloc(sizeof(floatvec *),new_nvals) ;
376      for( ibr=0 ; ibr < new_nvals ; ibr++ ){
377        fv = old_brick_mdfcurve[ivl[ibr]] ;
378        if( fv == NULL ){ nv = NULL; } else { COPY_floatvec(nv,fv); }
379        dblk->brick_mdfcurve[ibr] = nv ;
380      }
381    }
382 
383    /** setup master stuff now **/
384 
385    dblk->master_nvals = old_nvals ;
386    dblk->master_bytes = old_brick_bytes ;
387    dblk->master_ival  = (int *) RwcMalloc( sizeof(int) * new_nvals ) ;
388    for( ibr=0 ; ibr < new_nvals ; ibr++ ) dblk->master_ival[ibr] = ivl[ibr] ;
389 
390    /** destroy old datablock stuff now **/
391 
392    myRwcFree( old_brick_fac ) ;
393 
394    if( old_brick_lab != NULL ){
395      for( ibr=0 ; ibr < old_nvals ; ibr++ ) myRwcFree( old_brick_lab[ibr] ) ;
396      myRwcFree( old_brick_lab ) ;
397    }
398 
399    if( old_brick_keywords != NULL ){
400      for( ibr=0 ; ibr < old_nvals ; ibr++ ) myRwcFree( old_brick_keywords[ibr] ) ;
401      myRwcFree( old_brick_keywords ) ;
402    }
403 
404    if( old_brick_statcode != NULL ) myRwcFree( old_brick_statcode ) ;
405    if( old_brick_stataux  != NULL ){
406       for( ibr=0 ; ibr < old_nvals ; ibr++ ) myRwcFree( old_brick_stataux[ibr] ) ;
407       myRwcFree( old_brick_stataux ) ;
408    }
409 
410    if( old_brick_fdrcurve != NULL ){               /* 24 Jan 2008 */
411      for( ibr=0 ; ibr < old_nvals ; ibr++ )
412        KILL_floatvec( old_brick_fdrcurve[ibr] ) ;
413      free(old_brick_fdrcurve) ;
414    }
415    if( old_brick_mdfcurve != NULL ){               /* 22 Oct 2008 */
416      for( ibr=0 ; ibr < old_nvals ; ibr++ )
417        KILL_floatvec( old_brick_mdfcurve[ibr] ) ;
418      free(old_brick_mdfcurve) ;
419    }
420 
421    /** if dataset has statistics, rearrange them **/
422 
423    if( ISVALID_STATISTIC(dset->stats) ){
424       THD_statistics * new_stats , * old_stats ;
425       THD_brick_stats * bsold , * bsnew ;
426       float bot,top ;
427 
428       old_stats = dset->stats ;
429       new_stats = myRwcNew( THD_statistics ) ;
430       new_stats->type   = STATISTICS_TYPE ;
431       new_stats->parent = (RwcPointer) dset ;
432       new_stats->bstat  = NULL ;
433 
434       bsold = old_stats->bstat ;
435       bsnew = new_stats->bstat =
436          (THD_brick_stats *) RwcCalloc( new_nvals , sizeof(THD_brick_stats) ) ;
437 
438       new_stats->nbstat = new_nvals ;
439 
440       for( ibr=0 ; ibr < new_nvals ; ibr++ ){
441          if( ibr < old_stats->nbstat ) bsnew[ibr] = bsold[ivl[ibr]] ;
442          else                          INVALIDATE_BSTAT( bsnew[ibr] ) ;
443       }
444 
445       REPLACE_KILL( dset->kl , bsold     , bsnew     ) ;
446       REPLACE_KILL( dset->kl , old_stats , new_stats ) ;
447       dset->stats = new_stats ;
448 
449       myRwcFree(bsold) ; myRwcFree(old_stats) ;
450 
451       /* 21 Feb 2001: mangle statistics if sub-ranging is used */
452 
453       /* rcr - also if csv list is applied */
454 
455       bot = dset->dblk->master_bot ; top = dset->dblk->master_top ;
456       if( bot <= top ){
457               if( bot > 0.0 ) bot = 0.0 ;
458          else if( top < 0.0 ) top = 0.0 ;
459 
460          for( ibr=0 ; ibr < new_nvals ; ibr++ ){
461             if( ISVALID_BSTAT(bsnew[ibr]) ){
462                if( bsnew[ibr].min < bot ) bsnew[ibr].min = bot ;
463                if( bsnew[ibr].max > top ) bsnew[ibr].max = top ;
464             }
465          }
466       }
467    }
468 
469    RETURN(0) ;
470 }
471 
472 /*----------------------------------------------------------------------
473    Run 3dcalc to create a dataset and read it in.
474    -- RWCox - 17 Mar 2000
475    -- Modified 24 Jul 2009 to use unique name each time, fer shur
476 ------------------------------------------------------------------------*/
477 
478 #include <sys/types.h>
479 #include <sys/wait.h>
480 
THD_open_3dcalc(char * pname)481 static THD_3dim_dataset * THD_open_3dcalc( char *pname )
482 {
483    int    Argc=1               ,   newArgc=0 , ii,ll  ;
484    char  *Argv[1]={ "3dcalc" } , **newArgv=NULL ;
485    char  *qname , *tdir , prefix[128] , *uuid ;
486    pid_t  child_pid ;
487    THD_3dim_dataset *dset ;
488 
489 ENTRY("THD_open_3dcalc") ;
490 
491    /*-- remove the "3dcalc(" and the ")" from the input string --*/
492 
493    qname = (char *) malloc(sizeof(char)*(strlen(pname)+4096)) ;
494    strcpy(qname,pname+7) ;
495    ll = strlen(qname) ;
496    for( ii=ll-1 ; ii > 0 && isspace(qname[ii]) ; ii-- ) ; /*nada*/
497    if( ii == 0 ){ free(qname) ; RETURN(NULL) ; }  /* all blanks? */
498    if( qname[ii] == ')' && isspace(qname[ii-1]) )
499      qname[ii] = '\0' ;                   /* remove trailing ' )' */
500 
501    /*-- add -session to command string --*/
502 
503    tdir = my_getenv("TMPDIR") ;
504    if( tdir == NULL || strlen(tdir) > 512 ) tdir = "/tmp" ;
505    strcat(qname," -session ") ; strcat(qname,tdir) ; ll = strlen(tdir) ;
506 
507    /*-- add -prefix to command string --*/
508 
509    for( ii=0 ; ii < 9999 ; ii++ ){  /* create dataset name */
510      uuid = UNIQ_idcode() ;
511      sprintf(prefix,"3dcalc_%s",uuid) ; free(uuid) ;
512      if( THD_is_dataset(tdir,prefix,-1) == -1 ) break ;
513    }
514    if( ii >= 9999 ){  /* should never happen */
515      ERROR_message("Can't find unused 3dcalc_ dataset name in %s!",tdir) ;
516      free(qname) ; RETURN(NULL) ;
517    }
518 
519    strcat(qname," -prefix ") ; strcat(qname,prefix) ;
520    strcat(qname," -verbose") ;
521 
522    /*-- add a placeholder to be the last argument --*/
523 
524    strcat(qname," Zork") ;
525 
526    /*-- create the arg list for 3dcalc, starting with program name --*/
527 
528    append_string_to_args( qname , Argc , Argv , &newArgc , &newArgv ) ;
529 
530    free(qname) ; /* not needed no more */
531 
532    /*-- check if arg list was created OK --*/
533 
534    if( newArgv == NULL ) RETURN(NULL) ;  /* something bad? */
535 
536    if( newArgc < 3 ){                   /* too few args to 3dcalc */
537      for( ii=0 ; ii < newArgc ; ii++ ) free(newArgv[ii]) ;
538      free(newArgv) ; RETURN(NULL) ;
539    }
540 
541    /*-- replace placeholder in arg list with NULL pointer --*/
542 
543    free( newArgv[newArgc-1] ) ; newArgv[newArgc-1] = NULL ;
544 
545    /*-- fork and exec --*/
546 
547    INFO_message("Executing 3dcalc()") ;
548 #if 1
549    for(ii=0; ii< newArgc-1; ii++)
550      fprintf(stderr," argv[%d]=%s",ii,newArgv[ii]);
551    fprintf(stderr,"\n") ;
552 #endif
553 
554    child_pid = fork() ;
555 
556    if( child_pid == (pid_t)(-1) ){
557      perror("*** Can't fork 3dcalc()") ;
558      for( ii=0 ; ii < newArgc-1 ; ii++ ) free(newArgv[ii]) ;
559      free(newArgv) ; RETURN(NULL) ;
560    }
561 
562    if( child_pid == 0 ){  /*-- I'm the child --*/
563 
564      execvp( "3dcalc" , newArgv ) ;        /* should not return */
565      perror("*** Can't execvp 3dcalc()") ;
566      _exit(1) ;
567 
568    }
569 
570    /*-- I'm the parent --*/
571 
572    STATUS("Waiting for 3dcalc() process to run") ;
573 
574    (void) waitpid( child_pid , NULL , 0 ) ; /* wait for child to exit */
575 
576    ii = THD_is_dataset( tdir , prefix , -1 ) ;
577    if( ii == -1 ){
578      ERROR_message("3dcalc() failed - no dataset created!") ;
579      RETURN(NULL) ;
580    }
581    qname = THD_dataset_headname( tdir , prefix , ii ) ;
582    dset = THD_open_one_dataset( qname ) ;  /* try to read result */
583 
584    for( ii=0 ; ii < newArgc-1 ; ii++ ) free(newArgv[ii]) ;  /* toss trash */
585    free(newArgv) ; free(qname) ;
586 
587    if( dset == NULL ){                          /* read failed */
588      ERROR_message("3dcalc() failed - can't read dataset!") ;
589      RETURN(NULL) ;
590    }
591 
592    /* read dataset into memory */
593 
594    DSET_mallocize(dset) ; DSET_load(dset) ;
595    if( !DSET_LOADED(dset) ){                   /* can't read it? */
596      THD_delete_3dim_dataset( dset , True ) ; /* kill it dead */
597      ERROR_message("3dcalc() failed - can't load dataset!") ;
598      RETURN(NULL) ;
599    }
600 
601    /* lock dataset into memory, delete its files */
602 
603    DSET_lock(dset) ;
604    unlink( dset->dblk->diskptr->header_name ) ;
605    COMPRESS_unlink( dset->dblk->diskptr->brick_name ) ;
606 
607    /* 30 Jul 2003: changes its directory to cwd */
608 
609    EDIT_dset_items( dset , ADN_directory_name , "./" , ADN_none ) ;
610 
611    if( ISVALID_DSET(dset) &&
612       !ISVALID_MAT44(dset->daxes->ijk_to_dicom) )  /* 15 Dec 2005 */
613      THD_daxes_to_mat44(dset->daxes) ;
614 
615    RETURN(dset) ;
616 }
617 
618 /*-----------------------------------------------------------------
619    Convenience function, for copying only a single sub-brick.
620    Wrapper for THD_copy_dset_subs().
621 -------------------------------------------------------------------*/
THD_copy_one_sub(THD_3dim_dataset * din,int sub)622 THD_3dim_dataset * THD_copy_one_sub( THD_3dim_dataset * din, int sub )
623 {
624     int sublist[2] = {1, sub};
625     return THD_copy_dset_subs(din, sublist);
626 }
627 
628 /*-----------------------------------------------------------------
629    Copy a list of sub-bricks from a dataset.    26 Jul 2004 [rickr]
630    The first element of dlist is the number of sub-bricks to copy.
631 -------------------------------------------------------------------*/
THD_copy_dset_subs(THD_3dim_dataset * din,int * dlist)632 THD_3dim_dataset * THD_copy_dset_subs( THD_3dim_dataset * din, int * dlist )
633 {
634     THD_3dim_dataset * dout;
635     MRI_TYPE           kind;
636     char             * newdata;
637     int                sub, subs;
638     int                dsize, nxyz, rv;
639 
640 ENTRY("THD_copy_dset_subs");
641 
642     /* validate inputs */
643     if ( !din || !dlist )
644     {
645      fprintf(stderr, "** THD_copy_dset_subs: bad input (%p,%p)\n",
646              din,dlist);
647      RETURN(NULL);
648     }
649 
650     if ( dlist[0] <= 0 )
651     {
652       fprintf(stderr,"** THD_copy_dset_subs: invalid dlist length %d\n",
653               dlist[0]);
654       RETURN(NULL);
655     }
656 
657     /* verify that the input sub-brick list hold valid indices */
658     subs = dlist[0];
659     for ( sub = 0; sub < subs; sub++ )
660     {
661         if( dlist[sub+1] < 0 || dlist[sub+1] >= din->dblk->nvals )
662         {
663             fprintf(stderr,
664             "** THD_copy_dset_subs: index %d outside sub-brick range [0,%d]\n",
665                     dlist[sub+1], din->dblk->nvals);
666             RETURN(NULL);
667         }
668     }
669 
670     /* create initial dataset */
671     dout = EDIT_empty_copy(din);
672 
673     /* use mastery to copy selected labels, statistics, etc. */
674     rv = THD_setup_mastery(dout, dlist);
675     if ( rv != 0 )
676     {
677       fprintf(stderr, "** failure: THD_setup_mastery() returned %d\n", rv);
678       RETURN(NULL);
679     }
680 
681     /* be sure that we have some data to copy */
682     DSET_load(din);
683     if ( ! DSET_LOADED(din) )
684     {
685       fprintf(stderr,"** THD_copy_dset_subs: cannot load input dataset\n");
686       RETURN(NULL);
687     }
688 
689     /* do not create any warp structure here, since data will be inserted */
690 
691     dout->dblk->diskptr->byte_order   = mri_short_order();
692     dout->dblk->diskptr->storage_mode = STORAGE_BY_BRICK;
693 
694     /* now copy all of the sub-bricks */
695     nxyz = dout->daxes->nxx * dout->daxes->nyy * dout->daxes->nzz;
696     subs = dlist[0];
697     for ( sub = 0; sub < subs; sub++ )
698     {
699       kind = DSET_BRICK_TYPE(dout, sub);
700       dsize = mri_datum_size( kind );
701       if ( (newdata = (char *)malloc( nxyz * dsize )) == NULL )
702         {
703             fprintf( stderr, "r frdb: alloc failure: %d bytes!\n",
704                      nxyz * dsize );
705             DSET_delete(dout);
706             RETURN(NULL);
707         }
708 
709         memcpy(newdata,DSET_ARRAY(din,dlist[sub+1]), nxyz*dsize);
710         EDIT_substitute_brick(dout, sub, kind, (void *)newdata);
711     }
712 
713     /* clear mastery information, since data is already stored */
714     if( DBLK_IS_MASTERED(dout->dblk) ){
715         dout->dblk->master_nvals = 0;
716         myRwcFree( dout->dblk->master_ival );
717         myRwcFree( dout->dblk->master_bytes );
718     }
719 
720     dout->dblk->malloc_type = DATABLOCK_MEM_MALLOC;
721     dout->wod_flag = False;             /* since data is now in memory */
722 
723     RETURN(dout);
724 }
725 
726 /*------------------------------------------------------------------------*/
727 /* Given a dataset selector like "name[1..3]", return individual selectors
728    like "name[1]", "name[2]", "name[3]".  The reason for this is for older
729    programs like 3dttest that operate on a list of single brick datasets.
730    [19 Jul 2007 - RWCox]
731    Modified to allow use of labelized lists (per ZSS) -- 09 Dec 2011.
732 --------------------------------------------------------------------------*/
733 
THD_multiplex_dataset(char * pathname)734 THD_string_array * THD_multiplex_dataset( char *pathname )
735 {
736    char *cpt , *pname , *bname ;
737    int  *ivlist=NULL , ii ;
738    THD_string_array *sar ;
739    THD_3dim_dataset *qset ;
740 
741 ENTRY("THD_multiplex_dataset") ;
742    if( pathname == NULL ) RETURN(NULL) ;
743    cpt = strstr(pathname,"[") ; if( cpt == NULL ) RETURN(NULL) ;
744 
745    bname = strdup(pathname) ; cpt = strstr(bname,"[") ; *cpt = '\0' ;
746    if( STRING_HAS_SUFFIX(bname,".mnc")    ||
747        STRING_HAS_SUFFIX(bname,".mri")    ||
748        STRING_HAS_SUFFIX(bname,".svl")      ){
749      ERROR_message("Can't use sub-brick selectors '[...]' on dataset %s",bname) ;
750      free(bname) ; RETURN(NULL) ;
751    }
752    qset = THD_open_one_dataset(bname) ;  /* 09 Dec 2011 */
753    if( !ISVALID_DSET(qset) ){
754      ERROR_message("Can't open dataset %s",bname) ; free(bname) ; RETURN(NULL) ;
755    }
756    ivlist = MCW_get_thd_intlist(qset,cpt+1) ; DSET_delete(qset) ;
757    if( ivlist == NULL || ivlist[0] == 0 ){ free(bname); RETURN(NULL); }
758 
759    INIT_SARR(sar) ;
760    pname = malloc(sizeof(char)*(strlen(bname)+16)) ;
761    for( ii=1 ; ii <= ivlist[0] ; ii++ ){
762      sprintf(pname,"%s[%d]",bname,ivlist[ii]) ;
763      ADDTO_SARR(sar,pname) ;  /* makes a copy */
764    }
765 
766    free(pname); free(ivlist); free(bname); RETURN(sar);
767 }
768