/********************************************************************** Program to read GE RT-EPI image files and divine their ordering in time and space. To compile on Linux or other sane systems: cc -o Ifile -O2 Ifile.c -lm If on a Solaris machine, try cc -o Ifile -O2 Ifile.c -lm -DSOLARIS_DIRENT_ZERO ***********************************************************************/ #include #include #include #include #include #include #include #include #include #include /*------- prototypes [stuff included here from mrilib] -------*/ time_t THD_file_mtime( char * pathname ) ; int THD_is_file( char * pathname ) ; int THD_is_symlink( char * pathname ) ; long THD_filesize( char * pathname ) ; int THD_is_directory( char * pathname ) ; int THD_is_executable( char * pathname ) ; void MCW_file_expand( int nin , char ** fin , int * nout , char *** fout ) ; void MCW_free_expand( int gnum , char ** gout ) ; void MCW_warn_expand( int www ) ; void NIH_glob( char *fn , int *nout , char ***fout ) ; void NIH_glob_free( int gnum , char **gout ) ; /*------- typedefs -------*/ typedef struct { /* stuff extracted from GE I.* image */ int good ; /* is this a good image? */ int nx,ny ; /* image matrix */ int uv17; /* apparently codes for scan index */ float dx,dy,dz , zoff , tr,te ; /* various dimensions */ char orients[8] ; /* orientation string */ } ge_header_info ; void ge_header( char *pathname , ge_header_info *hi ) ; void Ifile_help (); /*#define DBG_FILE*/ /***************************************************************************/ int main( int argc , char *argv[] ) { int num_I , ii,jj , ngood , nrun , i, UseUv17 = 0; char **nam_I ; char **gnam_I , *PatOpt=NULL, *OutDir = NULL; int *time_I , *uv17, lmax=0 , ll , thresh , ibot,itop ; float *zoff_I , tr , zth1,zth2 , zd ; ge_header_info geh ; int Ni, CurVolInd, *New_Vol_Loc, *VolSize, N_Vols, *TroubVolume, iTroub, MultiSliceVol, *DupSlice, iDup, BadRun, AllGood = 1, GoodRun, kar = -1, brk = 0, StrtFiles = 0; float *Dzv, fact; char fmt[128] ; FILE * fout_dbg, *fout_panga; if (argc == 1) { Ifile_help(); exit(1); } kar = 1; brk = 0; StrtFiles = 0; UseUv17 = 0; while (kar < argc && !StrtFiles) { /* loop accross command ine options */ if (strcmp (argv[kar],"-h") == 0 || strcmp (argv[kar],"-help") == 0) { Ifile_help(); exit(1); } if (!brk && (strcmp(argv[kar], "-nt") == 0)) { UseUv17 = 1; brk = 1; ++kar; } if (!brk && (strcmp(argv[kar], "-od") == 0)) { kar ++; if (kar >= argc) { fprintf (stderr, "Error: Need argument after -od.\n"); exit (1); } OutDir = (char *)malloc((strlen(argv[kar])+1)*sizeof(char)); sprintf(OutDir,"%s",argv[kar]); brk = 1; ++kar; } if (!brk && (strcmp(argv[kar], "-sp") == 0)) { kar ++; if (kar >= argc) { fprintf (stderr, "Error: Need argument after -sp.\n"); exit (1); } PatOpt = (char *)malloc((strlen(argv[kar])+1)*sizeof(char)); sprintf(PatOpt,"%s",argv[kar]); brk = 1; ++kar; } /* nothing found, save location and get out */ if (!brk) { /* Done with options */ StrtFiles = kar; } else { brk = 0; } } if (UseUv17) { fprintf(stderr,"++ using User Variable 17.\n"); } else { fprintf(stderr,"++ using time stamp.\n");} if (!PatOpt) { PatOpt = (char *)malloc(sizeof(char)*10); sprintf(PatOpt,"alt+z"); } if (!OutDir) { OutDir = (char *)malloc(sizeof(char)*10); sprintf(OutDir,"afni"); } fprintf(stderr,"++ using slice pattern %s\n", PatOpt); fprintf(stderr,"++ using output directory %s\n", OutDir); /* for (i = 1; i < argc; ++i) { fprintf(stdout, "%s\n", argv[i]);} */ fout_panga = fopen("GERT_Reco","w"); if (fout_panga == NULL) { fprintf(stderr,"Could not open AutoPanga for writing. Check write permissions.\n"); exit(1); } fprintf(fout_panga, "#!/bin/csh -f\n"); fprintf(fout_panga, "#This script was automatically generated by Ifile.\n"); fprintf(fout_panga, "#Change the following options to your liking (see @RenamePanga -help for more info):\n\n"); fprintf(fout_panga, "set OutlierCheck = '-oc' #set to '-oc' to check for outliers, '' to skip checking.\n"); fprintf(fout_panga, "set OutPrefix = 'OutBrick' #Output brick prefix.\n\n"); /*-- get the list of files */ fprintf(stderr,"++ Expanding file list ...\n") ; MCW_file_expand( argc - StrtFiles, argv + StrtFiles , &num_I , &nam_I ); fprintf(stderr,"++ found %d '*/I.*' files\n",num_I) ; if( num_I <= 0 ) exit(1) ; /*-- get time and z-offset of each good image --*/ time_I = (int *) calloc( sizeof(int) , num_I ) ; zoff_I = (float *) calloc( sizeof(float) , num_I ) ; gnam_I = (char **) calloc( sizeof(char *) , num_I ) ; uv17 = (int *) calloc( sizeof(int) , num_I ) ; ngood = 0 ; fprintf(stderr,"++ Scanning GE headers") ; #ifdef DBG_FILE fout_dbg = fopen("DBG_IfileOut.txt","w"); #endif for( ii=0 ; ii < num_I ; ii++ ){ ge_header( nam_I[ii] , &geh ) ; /* read GE header */ if( ii%1000==999 ) fprintf(stderr,".") ; if( geh.good ){ /* is good image file */ zoff_I[ngood] = geh.zoff ; time_I[ngood] = (int) THD_file_mtime( nam_I[ii] ) ; gnam_I[ngood] = strdup( nam_I[ii] ) ; uv17[ngood] = geh.uv17; ngood++ ; ll = strlen(nam_I[ii]) ; if( ll > lmax ) lmax = ll ; tr += geh.tr ; } else { fprintf(stderr,"\tFile %s: !geh.good.\t", nam_I[ii] ) ; } #ifdef DBG_FILE fprintf(fout_dbg,"%s %d\n", nam_I[ii], time_I[ii]); #endif } fprintf(stderr,"\n++ %d files are good images\n",ngood) ; MCW_free_expand( num_I, nam_I ) ;/* don't need nam_I any more */ if( ngood < 3 ) exit(1) ; /*-- convert to time difference from previous image --*/ for( ii=ngood-1 ; ii > 0 ; ii-- ) { time_I[ii] -= time_I[ii-1] ; } time_I[0] = 0 ; /*-- set threshold for time, to find distinct imaging runs --*/ tr /= ngood ; /* average TR reported */ thresh = (int)( 3.0*tr+10.5 ) ; /* threshold (may need some work) */ if (UseUv17 == 0) { /* Just suppress time threshold output, time calculations are not trimmed since they are performed very quickly*/ fprintf(stderr,"++ File time threshold = %d s\n",thresh) ; } /*-- find time steps longer than thresh: these are starts of new imaging runs or with -nt option, use User Variable 17--*/ GoodRun = 0; nrun = 0 ; ibot = 0 ; while( ibot < ngood ){ /* scan forward from ibot */ /* scan itop until end, or until time step is too big */ if (UseUv17) { for( itop=ibot+1; itop zth1 && zd < zth2 ) printf(" image %s seems out of place\n",gnam_I[jj+1]) ; } } else { Ni = itop - ibot; /*Number of images in run, itop is not included*/ Dzv = (float *) calloc( sizeof(float) , Ni) ; New_Vol_Loc = (int *) calloc(sizeof(int), Ni); /* could not be bigger than Ni */ VolSize = (int *) calloc(sizeof(int), Ni); TroubVolume = (int *) calloc(sizeof(int), Ni); DupSlice = (int *) calloc(sizeof(int), Ni); Dzv[0] = 0; /* derivative of volume */ Dzv[1] = zoff_I[ibot+1] - zoff_I[ibot]; if (Dzv[1] < 0) { fact = -1; Dzv[1] *= fact; } else fact = 1; if (Dzv[1] != 0) MultiSliceVol = 1; else MultiSliceVol = 0; /* find total number of volumes */ iDup = 0; iTroub = 0; CurVolInd = 0; /* Current Volume Index */ New_Vol_Loc[CurVolInd] = ibot; /* New Volume Location in series */ for (jj = ibot+2 ; jj < itop ; jj++ ){ Dzv[jj-ibot] = fact * (zoff_I[jj] - zoff_I[jj - 1]); #ifdef DBG_FILE fprintf(fout_dbg,"Dzv %f \n", Dzv[jj-ibot]); #endif if (MultiSliceVol && !Dzv[jj-ibot]) { DupSlice[iDup] = jj; ++iDup; } if (Dzv[jj-ibot] < 0) { /* New Volume, coming Up */ ++CurVolInd; New_Vol_Loc[CurVolInd] = jj; VolSize[CurVolInd-1] = New_Vol_Loc[CurVolInd] - New_Vol_Loc[CurVolInd-1]; if (CurVolInd > 1) { /* compare to first volume */ if (VolSize[CurVolInd-1] != VolSize[0]) { /* trouble volume */ TroubVolume[iTroub] = CurVolInd - 1; ++iTroub; } } } } /* jj */ VolSize[CurVolInd] = itop - New_Vol_Loc[CurVolInd]; /* last volume size */ if (VolSize[CurVolInd] != VolSize[0]) { TroubVolume[iTroub] = CurVolInd; ++iTroub; } N_Vols = CurVolInd+1; printf("%d images %d Volume(s) \n", Ni, N_Vols); /* DoppelChecker */ if (N_Vols > 1) { /* for (i=0; i< N_Vols -1; i++) { fprintf(stderr, "Vol %d %d slices Begin %s End %s\n", i, VolSize[i], gnam_I[New_Vol_Loc[i]], gnam_I[New_Vol_Loc[i+1]-1]); } fprintf(stderr, "Vol %d %d slices Begin %s End %s\n", N_Vols-1, VolSize[N_Vols-1], gnam_I[New_Vol_Loc[N_Vols-1]],gnam_I[itop-1]); */ } else { /* fprintf(stderr, "One volume found: %d slices, Begin %s End %s\n", VolSize[0], gnam_I[New_Vol_Loc[0]],gnam_I[itop-1]); */ } if (iTroub > 0) { /* Trouble volumes found */ BadRun = 1; fprintf(stderr, "\t\33[1m***************** PANGA! Trouble volumes found. *****************\33[0m\n"); fprintf(stderr, "\tVol %d %s--%s (%d slices) has a different size from the first volume (%d slices) in the series.\n", \ TroubVolume[0], gnam_I[New_Vol_Loc[TroubVolume[0]]], gnam_I[New_Vol_Loc[TroubVolume[0]]+VolSize[TroubVolume[0]]-1], VolSize[TroubVolume[0]], VolSize[0]); if (iTroub > 1) fprintf(stderr, "\t%d other volumes suffer of similar ailments! Think of the children!\n", iTroub - 1); /* Too much info for (i=0; i < iTroub; i++) { fprintf(stderr, "Vol %d (%d slices) has a different size from the first volume (%d slices) in the series.\n", TroubVolume[i], VolSize[TroubVolume[i]], VolSize[0]); } */ } if (iDup > 0) { /* Duplicate slices found */ BadRun = 1; fprintf(stderr, "\t\33[1m***************** PANGA! Dupilcated slices found. *****************\33[0m\n"); for (i=0; i < iDup; i++) { fprintf(stderr, "\tSlice %s appears to be a duplicate of slice %s.\n", gnam_I[DupSlice[i]], gnam_I[DupSlice[i]-1]); } } /* iDup > 0 */ }/* New Method */ if (!BadRun) { /* write out results as a command line for @RenamePanga */ ++ GoodRun; fprintf(fout_panga,"@RenamePanga %s ", strtok(gnam_I[ibot],"/")); if (MultiSliceVol) fprintf(fout_panga,"%s %d %d $OutPrefix -sp %s $OutlierCheck -od %s\n", strtok(NULL,"/I."), (int)Ni/N_Vols, N_Vols, PatOpt, OutDir); else fprintf(fout_panga,"%s %d %d $OutPrefix -sp %s $OutlierCheck -od %s\n", strtok(NULL,"/I."), N_Vols, (int)Ni/N_Vols, PatOpt, OutDir); } else { AllGood = 0; } free(Dzv); free(New_Vol_Loc); free(VolSize); free(TroubVolume); free(DupSlice); } ibot = itop ; /* start scan here */ } free(PatOpt); free(OutDir); #ifdef DBG_FILE fclose (fout_dbg); #endif fprintf(fout_panga, "\n"); fclose (fout_panga); system ("chmod u+x GERT_Reco"); #if 0 /* old code to print out stuff to check if program was working */ sprintf(fmt,"%%-%d.%ds: dt=%%d zoff=%%g\n",lmax,lmax) ; for( ii=0 ; ii < ngood ; ii++ ) printf(fmt,gnam_I[ii],time_I[ii],zoff_I[ii]) ; #endif if (!GoodRun) system ("rm -f GERT_Reco"); else fprintf(stdout,"\nFound %d complete scans.\nRun\33[1m GERT_Reco \33[0mto create AFNI bricks.\n\n", GoodRun); if (AllGood) exit(0) ; else exit(1); } /***************************************************************************/ void Ifile_help () { fprintf(stdout,"\nUsage: Ifile [Options] \n"); fprintf(stdout,"\n\t[-nt]: Do not use time stamp to identify complete scans.\n"); fprintf(stdout,"\t Complete scans are identified from 'User Variable 17'\n" "\t in the image header.\n"); fprintf(stdout,"\t[-sp Pattern]: Slice acquisition pattern.\n" "\t Sets the slice acquisition pattern.\n" "\t The default option is alt+z.\n" "\t See to3d -help for acceptable options.\n"); fprintf(stdout,"\t[-od Output_Directory]: Set the output directory in @RenamePanga.\n" "\t The default is afni .\n"); fprintf(stdout,"\n\t: Strings of wildcards defining series of\n"); fprintf(stdout,"\t GE-Real Time (GERT) images to be assembled\n"); fprintf(stdout,"\t as an afni brick. Example:\n"); fprintf(stdout,"\t Ifile '*/I.*'\n"); fprintf(stdout,"\t or Ifile '083/I.*' '103/I.*' '123/I.*' '143/I.*'\n\n"); fprintf(stdout,"\tThe program attempts to identify complete scans from the list\n"); fprintf(stdout,"\tof images supplied on command line and generates the commands\n"); fprintf(stdout,"\tnecessary to turn them into AFNI bricks using the script @RenamePanga.\n"); fprintf(stdout,"\tIf at least one complete scan is identified, a script file named GERT_Reco\n"); fprintf(stdout,"\tis created and executing it creates the afni bricks placed in the afni directory.\n"); fprintf(stdout,"\nHow does it work?\n"); fprintf(stdout,"\tWith the -nt option: Ifile uses the variable 'User Variable 17' in the \n"); fprintf(stdout,"\tI file's header. This option appears to be augmented each time a new\n"); fprintf(stdout,"\tscan is started. (Thanks to S. Marrett for discovering the elusive variable.)\n"); fprintf(stdout,"\tWithout -nt option: Ifile first examines the modification time for each image and \n"); fprintf(stdout,"\tinfers from that which images form a single scan. Consecutive images that are less \n"); fprintf(stdout,"\tthan T seconds apart belong to the same scan. T is set based on the mean\n"); fprintf(stdout,"\ttime delay difference between successive images. The threshold currently\n"); fprintf(stdout,"\tused works for the test data that we have. If it fails for your data, let us\n"); fprintf(stdout,"\tknow and supply us with the data. Once a set of images is grouped into a \n"); fprintf(stdout,"\tscan the sequence of slice location is analysed and duplicate, missing slices,\n"); fprintf(stdout,"\tand incomplete volumes are detected. Sets of images that do not pass these tests\n"); fprintf(stdout,"\tare ignored.\n"); fprintf(stdout,"\nPreserving Time Info: (not necessary with -nt option but does not hurt to preserve anyway)\n"); fprintf(stdout,"\tIt is important to preserve the file modification time info as you copy or untar\n"); fprintf(stdout,"\tthe data. If you neglect to do so and fail to write down where each scan ends\n"); fprintf(stdout,"\tand/or begins, you might have a hell of a time reconstructing your data.\n"); fprintf(stdout,"\tWhen copying image directories, use \33[1m cp -rp ???/* \33[0m and when untaring \n"); fprintf(stdout,"\tthe archive, use \33[1m tar --atime-preserve -xf Archive.tar \33[0m on linux.\n"); fprintf(stdout,"\tOn Sun and SGI, tar -xf Archive.tar preserves the time info.\n"); fprintf(stdout,"\nFuture Improvements:\n"); fprintf(stdout,"\tOut of justifiable laziness, and for other less convincing reasons, I have left \n"); fprintf(stdout,"\tIfile and @RenamePanga separate. They can be combined into one program but it's usage\n"); fprintf(stdout,"\twould become more complicated. At any rate, the user should not notice any difference\n"); fprintf(stdout,"\tsince all they have to do is run the script GERT_reco that is created by Ifile.\n\n"); fprintf(stdout,"\t Dec. 12/01 (Last modified July 24/02) SSCC/NIMH \n\tRobert W. Cox(rwcox@nih.gov) and Ziad S. Saad (ziad@nih.gov)\n\n"); } /*** from thd_filestuff.c ***/ time_t THD_file_mtime( char * pathname ) { static struct stat buf ; int ii ; if( pathname == NULL ) return 0 ; ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ; return buf.st_mtime ; } /*-------------------------------------------*/ int THD_is_file( char * pathname ) { static struct stat buf ; int ii ; if( pathname == NULL ) return 0 ; ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ; ii = (buf.st_mode & S_IFREG) != 0 ; return ii ; } /*-------------------------------------------*/ int THD_is_symlink( char * pathname ) { char buf[32] ; int ii ; ii = readlink( pathname , buf , 32 ) ; return (ii > 0) ; } /*-------------------------------------------*/ long THD_filesize( char * pathname ) { static struct stat buf ; int ii ; if( pathname == NULL ) return -1 ; ii = stat( pathname , &buf ) ; if( ii != 0 ) return -1 ; return buf.st_size ; } /*-------------------------------------------*/ int THD_is_directory( char * pathname ) { static struct stat buf ; int ii ; if( pathname == NULL ) return 0 ; ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ; ii = (buf.st_mode & S_IFDIR) != 0 ; return ii ; } /*-------------------------------------------*/ int THD_is_executable( char * pathname ) { static struct stat buf ; int ii ; if( pathname == NULL ) return 0 ; ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ; ii = (buf.st_mode & S_IXOTH) != 0 ; return ii ; } /***************************************************************************/ /*** from mcw_glob.[ch] ***/ /* * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Guido van Rossum. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)glob.h 5.6 (Berkeley) 4/3/91 */ typedef struct { int gl_pathc; /* count of total paths so far */ int gl_matchc; /* count of paths matching pattern */ int gl_offs; /* reserved at beginning of gl_pathv */ int gl_flags; /* copy of flags parameter to glob() */ int (*gl_errfunc)(); /* copy of errfunc parameter to glob() */ char **gl_pathv; /* list of paths matching pattern */ } glob_t; #define GLOB_APPEND 0x001 /* append to output from previous call */ #define GLOB_DOOFFS 0x002 /* use gl_offs */ #define GLOB_ERR 0x004 /* return on error */ #define GLOB_MAGCHAR 0x008 /* pattern had globbing characters */ #define GLOB_MARK 0x010 /* append / to matching directories */ #define GLOB_NOCHECK 0x020 /* return pattern itself if nothing matches */ #define GLOB_NOSORT 0x040 /* don't sort */ #define GLOB_QUOTE 0x080 /* quote special chars with \ */ #define GLOB_NOMAGIC 0x100 /* like GLOB_NOCHECK but only if the pattern * did not have any magic characters */ #define GLOB_ALTNOT 0x200 /* use alternate glob character [^ not !] */ #define GLOB_NOSPACE (-1) /* malloc call failed */ #define GLOB_ABEND (-2) /* unignored error */ int glob (const char *, int, int (*)(char *, int), glob_t *); void globfree (glob_t *); /* * Glob: the interface is a superset of the one defined in POSIX 1003.2, * draft 9. * * The [!...] convention to negate a range is supported (SysV, Posix, ksh). * * Optional extra services, controlled by flags not defined by POSIX: * * GLOB_QUOTE: * Escaping convention: \ inhibits any special meaning the following * character might have (except \ at end of string is retained). * GLOB_MAGCHAR: * Set in gl_flags if pattern contained a globbing character. * GLOB_ALTNOT: * Use ^ instead of ! for "not". * gl_matchc: * Number of matches in the current invocation of glob. */ /** the following were in "sh.h", but I put them here to get rid of the need for that file -- RWCox **/ #undef __P /* in case already defined elsewhere (by gcc, say)*/ #define __P(a) a #define xfree free #define xmalloc malloc #define xrealloc realloc #ifdef SPARKY #undef _POSIX_SOURCE #endif #include #include #include #include #include typedef void * ptr_t; /** don't use sh.h any more **/ #if 0 # define Char __Char # include "sh.h" # undef Char # undef QUOTE # undef TILDE # undef META # undef CHAR # undef ismeta # undef Strchr #endif #ifndef S_ISDIR #define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR) #endif #if !defined(S_ISLNK) && defined(S_IFLNK) #define S_ISLNK(a) (((a) & S_IFMT) == S_IFLNK) #endif #if !defined(S_ISLNK) && !defined(lstat) #define lstat stat #endif typedef unsigned short Char; static int glob1 __P((Char *, glob_t *, int)); static int glob2 __P((Char *, Char *, Char *, glob_t *, int)); static int glob3 __P((Char *, Char *, Char *, Char *, glob_t *, int)); static int globextend __P((Char *, glob_t *)); static int match __P((Char *, Char *, Char *, int)); #ifndef __clipper__ static int compare __P((const ptr_t, const ptr_t)); #endif static DIR *Opendir __P((Char *)); #ifdef S_IFLNK static int Lstat __P((Char *, struct stat *)); #endif static Char *Strchr __P((Char *, int)); #ifdef DEBUG static void qprintf __P((Char *)); #endif #define DOLLAR '$' #define DOT '.' #define EOS '\0' #define LBRACKET '[' #define NOT '!' #define ALTNOT '^' #define QUESTION '?' #define QUOTE '\\' #define RANGE '-' #define RBRACKET ']' #define SEP '/' #define STAR '*' #define TILDE '~' #define UNDERSCORE '_' #define M_META 0x8000 #define M_PROTECT 0x4000 #define M_MASK 0xffff #define M_ASCII 0x00ff #define CHAR(c) ((c)&M_ASCII) #define META(c) ((c)|M_META) #define M_ALL META('*') #define M_END META(']') #define M_NOT META('!') #define M_ALTNOT META('^') #define M_ONE META('?') #define M_RNG META('-') #define M_SET META('[') #define ismeta(c) (((c)&M_META) != 0) #include "machdep.h" #if defined(SOLARIS_DIRENT_ZERO) && !defined(SOLARIS_DIRENT_PATCH) # define SOLARIS_DIRENT_PATCH #endif #ifdef SOLARIS_DIRENT_PATCH struct dirent { ino_t d_ino; off_t d_off; unsigned short d_reclen; char d_name[1]; }; #endif /* * Need to dodge two kernel bugs: * opendir("") != opendir(".") * NAMEI_BUG: on plain files trailing slashes are ignored in some kernels. * POSIX specifies that they should be ignored in directories. */ static DIR * Opendir(str) register Char *str; { char buf[MAXPATHLEN]; register char *dc = buf; if (!*str) return (opendir(".")); while ((*dc++ = *str++) != '\0') continue; return (opendir(buf)); } #ifdef S_IFLNK static int Lstat(fn, sb) register Char *fn; struct stat *sb; { char buf[MAXPATHLEN]; register char *dc = buf; while ((*dc++ = *fn++) != '\0') continue; # ifdef NAMEI_BUG { int st; st = lstat(buf, sb); if (*buf) dc--; return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st); } # else return (lstat(buf, sb)); # endif /* NAMEI_BUG */ } #else #define Lstat Stat #endif /* S_IFLNK */ static int Stat(fn, sb) register Char *fn; struct stat *sb; { char buf[MAXPATHLEN]; register char *dc = buf; while ((*dc++ = *fn++) != '\0') continue; #ifdef NAMEI_BUG { int st; st = stat(buf, sb); if (*buf) dc--; return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st); } #else return (stat(buf, sb)); #endif /* NAMEI_BUG */ } static Char * Strchr(str, ch) Char *str; int ch; { do if (*str == ch) return (str); while (*str++); return (NULL); } #ifdef DEBUG static void qprintf(s) Char *s; { Char *p; for (p = s; *p; p++) printf("%c", *p & 0xff); printf("\n"); for (p = s; *p; p++) printf("%c", *p & M_PROTECT ? '"' : ' '); printf("\n"); for (p = s; *p; p++) printf("%c", *p & M_META ? '_' : ' '); printf("\n"); } #endif /* DEBUG */ static int compare(p, q) const ptr_t p, q; { #if defined(NLS) && !defined(NOSTRCOLL) errno = 0; /* strcoll sets errno, another brain-damage */ return (strcoll(*(char **) p, *(char **) q)); #else return (strcmp(*(char **) p, *(char **) q)); #endif /* NLS && !NOSTRCOLL */ } /* * The main glob() routine: compiles the pattern (optionally processing * quotes), calls glob1() to do the real pattern matching, and finally * sorts the list (unless unsorted operation is requested). Returns 0 * if things went well, nonzero if errors occurred. It is not an error * to find no matches. */ int glob(pattern, flags, errfunc, pglob) const char *pattern; int flags; int (*errfunc) __P((char *, int)); glob_t *pglob; { int err, oldpathc; Char *bufnext, *bufend, *compilebuf, m_not; const unsigned char *compilepat, *patnext; int c, not; Char patbuf[MAXPATHLEN + 1], *qpatnext; int no_match; patnext = (unsigned char *) pattern; if (!(flags & GLOB_APPEND)) { pglob->gl_pathc = 0; pglob->gl_pathv = NULL; if (!(flags & GLOB_DOOFFS)) pglob->gl_offs = 0; } pglob->gl_flags = flags & ~GLOB_MAGCHAR; pglob->gl_errfunc = errfunc; oldpathc = pglob->gl_pathc; pglob->gl_matchc = 0; if (pglob->gl_flags & GLOB_ALTNOT) { not = ALTNOT; m_not = M_ALTNOT; } else { not = NOT; m_not = M_NOT; } bufnext = patbuf; bufend = bufnext + MAXPATHLEN; compilebuf = bufnext; compilepat = patnext; no_match = *patnext == not; if (no_match) patnext++; if (flags & GLOB_QUOTE) { /* Protect the quoted characters */ while (bufnext < bufend && (c = *patnext++) != EOS) if (c == QUOTE) { if ((c = *patnext++) == EOS) { c = QUOTE; --patnext; } *bufnext++ = (Char) (c | M_PROTECT); } else *bufnext++ = (Char) c; } else while (bufnext < bufend && (c = *patnext++) != EOS) *bufnext++ = (Char) c; *bufnext = EOS; bufnext = patbuf; qpatnext = patbuf; /* we don't need to check for buffer overflow any more */ while ((c = *qpatnext++) != EOS) { switch (c) { case LBRACKET: c = *qpatnext; if (c == not) ++qpatnext; if (*qpatnext == EOS || Strchr(qpatnext + 1, RBRACKET) == NULL) { *bufnext++ = LBRACKET; if (c == not) --qpatnext; break; } pglob->gl_flags |= GLOB_MAGCHAR; *bufnext++ = M_SET; if (c == not) *bufnext++ = m_not; c = *qpatnext++; do { *bufnext++ = CHAR(c); if (*qpatnext == RANGE && (c = qpatnext[1]) != RBRACKET) { *bufnext++ = M_RNG; *bufnext++ = CHAR(c); qpatnext += 2; } } while ((c = *qpatnext++) != RBRACKET); *bufnext++ = M_END; break; case QUESTION: pglob->gl_flags |= GLOB_MAGCHAR; *bufnext++ = M_ONE; break; case STAR: pglob->gl_flags |= GLOB_MAGCHAR; /* collapse adjacent stars to one, to avoid * exponential behavior */ if (bufnext == patbuf || bufnext[-1] != M_ALL) *bufnext++ = M_ALL; break; default: *bufnext++ = CHAR(c); break; } } *bufnext = EOS; #ifdef DEBUG qprintf(patbuf); #endif if ((err = glob1(patbuf, pglob, no_match)) != 0) return (err); /* * If there was no match we are going to append the pattern * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified * and the pattern did not contain any magic characters * GLOB_NOMAGIC is there just for compatibility with csh. */ if (pglob->gl_pathc == oldpathc && ((flags & GLOB_NOCHECK) || ((flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) { if (!(flags & GLOB_QUOTE)) { Char *dp = compilebuf; const unsigned char *sp = compilepat; while ((*dp++ = *sp++) != '\0') continue; } else { /* * copy pattern, interpreting quotes; this is slightly different * than the interpretation of quotes above -- which should prevail? */ while (*compilepat != EOS) { if (*compilepat == QUOTE) { if (*++compilepat == EOS) --compilepat; } *compilebuf++ = (unsigned char) *compilepat++; } *compilebuf = EOS; } return (globextend(patbuf, pglob)); } else if (!(flags & GLOB_NOSORT)) qsort((char *) (pglob->gl_pathv + pglob->gl_offs + oldpathc), pglob->gl_pathc - oldpathc, sizeof(char *), (int (*) __P((const void *, const void *))) compare); return (0); } static int glob1(pattern, pglob, no_match) Char *pattern; glob_t *pglob; int no_match; { Char pathbuf[MAXPATHLEN + 1]; /* * a null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ if (*pattern == EOS) return (0); return (glob2(pathbuf, pathbuf, pattern, pglob, no_match)); } /* * functions glob2 and glob3 are mutually recursive; there is one level * of recursion for each segment in the pattern that contains one or * more meta characters. */ static int glob2(pathbuf, pathend, pattern, pglob, no_match) Char *pathbuf, *pathend, *pattern; glob_t *pglob; int no_match; { struct stat sbuf; int anymeta; Char *p, *q; /* * loop over pattern segments until end of pattern or until segment with * meta character found. */ anymeta = 0; for (;;) { if (*pattern == EOS) { /* end of pattern? */ *pathend = EOS; if (Lstat(pathbuf, &sbuf)) return (0); if (((pglob->gl_flags & GLOB_MARK) && pathend[-1] != SEP) && (S_ISDIR(sbuf.st_mode) #ifdef S_IFLNK || (S_ISLNK(sbuf.st_mode) && (Stat(pathbuf, &sbuf) == 0) && S_ISDIR(sbuf.st_mode)) #endif )) { *pathend++ = SEP; *pathend = EOS; } ++pglob->gl_matchc; return (globextend(pathbuf, pglob)); } /* find end of next segment, copy tentatively to pathend */ q = pathend; p = pattern; while (*p != EOS && *p != SEP) { if (ismeta(*p)) anymeta = 1; *q++ = *p++; } if (!anymeta) { /* no expansion, do next segment */ pathend = q; pattern = p; while (*pattern == SEP) *pathend++ = *pattern++; } else /* need expansion, recurse */ return (glob3(pathbuf, pathend, pattern, p, pglob, no_match)); } /* NOTREACHED */ } static int glob3(pathbuf, pathend, pattern, restpattern, pglob, no_match) Char *pathbuf, *pathend, *pattern, *restpattern; glob_t *pglob; int no_match; { extern int errno; DIR *dirp; struct dirent *dp; int err; Char m_not = (pglob->gl_flags & GLOB_ALTNOT) ? M_ALTNOT : M_NOT; char cpathbuf[MAXPATHLEN], *ptr; #ifdef SOLARIS_DIRENT_PATCH /* declaration of vars used in the solaris-patch */ char dname[255]; int ii; #endif *pathend = EOS; errno = 0; if (!(dirp = Opendir(pathbuf))) { /* todo: don't call for ENOENT or ENOTDIR? */ for (ptr = cpathbuf; (*ptr++ = (char) *pathbuf++) != EOS;) continue; if ((pglob->gl_errfunc && (*pglob->gl_errfunc) (cpathbuf, errno)) || (pglob->gl_flags & GLOB_ERR)) return (GLOB_ABEND); else return (0); } err = 0; /* search directory for matching names */ while ((dp = readdir(dirp)) != NULL) { register unsigned char *sc; register Char *dc; #ifdef SOLARIS_DIRENT_PATCH /********** begin patch **********/ #ifndef SOLARIS_DIRENT_ZERO for (ii = -2 ; dp->d_name[ii] != '\0' ; ++ii) { dname[ii+2] = dp->d_name[ii]; } dname[ii+2] = '\0'; #else strcpy(dname, dp->d_name); /* John Koger, March 1999 */ #endif /********** end patch now use dname for dp->d_name **********/ /* initial DOT must be matched literally */ if (dname[0] == DOT && *pattern != DOT) continue; for (sc = (unsigned char *) dname, dc = pathend; #else if (dp->d_name[0] == DOT && *pattern != DOT) continue; for (sc = (unsigned char *) dp->d_name, dc = pathend; #endif (*dc++ = *sc++) != '\0';) continue; if (match(pathend, pattern, restpattern, (int) m_not) == no_match) { *pathend = EOS; continue; } err = glob2(pathbuf, --dc, restpattern, pglob, no_match); if (err) break; } /* todo: check error from readdir? */ (void) closedir(dirp); return (err); } /* * Extend the gl_pathv member of a glob_t structure to accomodate a new item, * add the new item, and update gl_pathc. * * This assumes the BSD realloc, which only copies the block when its size * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic * behavior. * * Return 0 if new item added, error code if memory couldn't be allocated. * * Invariant of the glob_t structure: * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and * gl_pathv points to (gl_offs + gl_pathc + 1) items. */ static int globextend(path, pglob) Char *path; glob_t *pglob; { register char **pathv; register int i; unsigned int newsize; char *copy; Char *p; newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); pathv = (char **) (pglob->gl_pathv ? xrealloc((ptr_t) pglob->gl_pathv, (size_t) newsize) : xmalloc((size_t) newsize)); if (pathv == NULL) return (GLOB_NOSPACE); if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { /* first time around -- clear initial gl_offs items */ pathv += pglob->gl_offs; for (i = pglob->gl_offs; --i >= 0;) *--pathv = NULL; } pglob->gl_pathv = pathv; for (p = path; *p++;) continue; if ((copy = (char *) xmalloc((size_t) (p - path))) != NULL) { register char *dc = copy; register Char *sc = path; while ((*dc++ = *sc++) != '\0') continue; pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; } pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; return ((copy == NULL) ? GLOB_NOSPACE : 0); } /* * pattern matching function for filenames. Each occurrence of the * * pattern causes a recursion level. */ static int match(name, pat, patend, m_not) register Char *name, *pat, *patend; int m_not; { int ok, negate_range; Char c, k; while (pat < patend) { c = *pat++; switch (c & M_MASK) { case M_ALL: if (pat == patend) return (1); do if (match(name, pat, patend, m_not)) return (1); while (*name++ != EOS); return (0); case M_ONE: if (*name++ == EOS) return (0); break; case M_SET: ok = 0; if ((k = *name++) == EOS) return (0); if ((negate_range = ((*pat & M_MASK) == m_not)) != 0) ++pat; while (((c = *pat++) & M_MASK) != M_END) { if ((*pat & M_MASK) == M_RNG) { if (c <= k && k <= pat[1]) ok = 1; pat += 2; } else if (c == k) ok = 1; } if (ok == negate_range) return (0); break; default: k = *name++; if (k != c) return (0); break; } } return (*name == EOS); } /* free allocated data belonging to a glob_t structure */ void globfree(pglob) glob_t *pglob; { register int i; register char **pp; if (pglob->gl_pathv != NULL) { pp = pglob->gl_pathv + pglob->gl_offs; for (i = pglob->gl_pathc; i--; ++pp) if (*pp) xfree((ptr_t) *pp), *pp = NULL; xfree((ptr_t) pglob->gl_pathv), pglob->gl_pathv = NULL; } } static int warn = 0 ; void MCW_warn_expand( int www ){ warn = www; return; } /*------------------------------------------------------------------------ Routines that allows filename wildcarding to be handled inside to3d. The advantage: limitations of shell command line lengths. 29 July 1996: Incorporated "glob" functions from tcsh-6.05, rather than rely on system supplying a library. 30 July 1996: Extended routine to allow for 3D: type prefixes. 10 Feb 2000: and for 3A: prefixes. --------------------------------------------------------------------------*/ void NIH_glob( char *fn , int *nout , char ***fout ) { MCW_file_expand( 1 , &fn , nout , fout ) ; } void NIH_glob_free( int gnum , char **gout ) { MCW_free_expand( gnum , gout ) ; } /*------------------------------------------------------------------------*/ void MCW_file_expand( int nin , char ** fin , int * nout , char *** fout ) { glob_t gl ; int ii , gnum, gold , ilen ; char ** gout ; char * fn ; char prefix[4] , fpre[128] , fname[256] ; int b1,b2,b3,b4,b5 , ib,ig , lpre ; if( nin <= 0 ){ *nout = 0 ; return ; } gnum = 0 ; gout = NULL ; for( ii=0 ; ii < nin ; ii++ ){ fn = fin[ii] ; ig = 0 ; /** look for 3D: prefix **/ if( strlen(fn) > 9 && fn[0] == '3' && fn[1] == 'D' ){ ib = 0 ; prefix[ib++] = '3' ; prefix[ib++] = 'D' ; if( fn[2] == ':' ){ prefix[ib++] = '\0' ; } else { prefix[ib++] = fn[2] ; prefix[ib++] = '\0' ; } ig = sscanf( fn+ib , "%d:%d:%d:%d:%d:%s" , /* must scan all */ &b1,&b2,&b3,&b4,&b5 , fname ) ; /* six items OK */ /** if have all 6 3D: items, then make a 3D: prefix for output **/ if( ig == 6 ){ sprintf(fpre , "%s:%d:%d:%d:%d:%d:" , prefix,b1,b2,b3,b4,b5) ; lpre = strlen(fpre) ; } else { ig = 0 ; } } if( strlen(fn) > 9 && fn[0] == '3' && fn[1] == 'A' && fn[3] == ':' ){ ib = 0 ; prefix[ib++] = '3' ; prefix[ib++] = 'A' ; prefix[ib++] = fn[2] ; prefix[ib++] = '\0' ; ig = sscanf( fn+ib , "%d:%d:%d:%s" , /* must scan all */ &b1,&b2,&b3, fname ) ; /* four items OK */ /** if have all 4 3A: items, then make a 3A: prefix for output **/ if( ig == 4 ){ sprintf(fpre , "%s:%d:%d:%d:" , prefix,b1,b2,b3) ; lpre = strlen(fpre) ; } else { ig = 0 ; } } if( ig > 0 ) (void) glob( fname , 0 , NULL , &gl ) ; /* 3D: was OK */ else (void) glob( fn , 0 , NULL , &gl ) ; /* not OK */ /** put each matched string into the output array **/ if( gl.gl_pathc > 0 ){ /** make space for output now **/ gold = gnum ; gnum += gl.gl_pathc ; if( gout == NULL ) gout = (char **) malloc ( sizeof(char *)*gnum); else gout = (char **) realloc(gout, sizeof(char *)*gnum); for( ib=0 ; ib < gl.gl_pathc ; ib++ ){ ilen = strlen( gl.gl_pathv[ib] ) + 1 ; /* length of this name */ if( ig > 0 ) ilen += lpre ; /* plus 3D: prefix? */ gout[ib+gold] = (char *) malloc( sizeof(char) * ilen ) ; /* output! */ if( ig > 0 ){ strcpy( gout[ib+gold] , fpre ) ; /* 3D: prefix */ strcat( gout[ib+gold] , gl.gl_pathv[ib] ) ; /* then name */ } else { strcpy( gout[ib+gold] , gl.gl_pathv[ib] ) ; /* just name */ } } } else if( ig == 6 && strcmp(fname,"ALLZERO") == 0 ){ /* 06 Mar 2001 */ gold = gnum ; gnum++ ; if( gout == NULL ) gout = (char **) malloc ( sizeof(char *)*gnum); else gout = (char **) realloc(gout, sizeof(char *)*gnum); ilen = lpre + strlen(fname) + 1 ; gout[gold] = (char *) malloc( sizeof(char) * ilen ) ; /* output! */ strcpy( gout[gold] , fpre ) ; strcat( gout[gold] , fname ) ; } else { /* 30 Apr 2001 */ if( warn ) /* 13 Jul 2001 - print only if told to do so */ fprintf(stderr,"** Can't find file %s\n", (ig>0) ? fname : fn ) ; } globfree( &gl ) ; } *nout = gnum ; *fout = gout ; return ; } void MCW_free_expand( int gnum , char ** gout ) { int ii ; if( gout == NULL ) return ; for( ii=0 ; ii < gnum ; ii++ ) free( gout[ii] ) ; free( gout ) ; return ; } /***************************************************************************/ /*** adapted from ge_header.c ***/ /*---------------------------------------------------------------*/ static void swap_4(void *ppp) { unsigned char *pntr = (unsigned char *) ppp ; unsigned char b0, b1, b2, b3; b0 = *pntr; b1 = *(pntr+1); b2 = *(pntr+2); b3 = *(pntr+3); *pntr = b3; *(pntr+1) = b2; *(pntr+2) = b1; *(pntr+3) = b0; } /*---------------------------------------------------------------*/ static void swap_8(void *ppp) { unsigned char *pntr = (unsigned char *) ppp ; unsigned char b0, b1, b2, b3; unsigned char b4, b5, b6, b7; b0 = *pntr ; b1 = *(pntr+1); b2 = *(pntr+2); b3 = *(pntr+3); b4 = *(pntr+4); b5 = *(pntr+5); b6 = *(pntr+6); b7 = *(pntr+7); *pntr = b7; *(pntr+1) = b6; *(pntr+2) = b5; *(pntr+3) = b4; *(pntr+4) = b3; *(pntr+5) = b2; *(pntr+6) = b1; *(pntr+7) = b0; } /*---------------------------------------------------------------*/ static void swap_2(void *ppp) { unsigned char *pntr = (unsigned char *) ppp ; unsigned char b0, b1; b0 = *pntr; b1 = *(pntr+1); *pntr = b1; *(pntr+1) = b0; } /******************************************************************/ /*** Return info from a GEMS IMGF file into user-supplied struct **/ void ge_header( char *pathname , ge_header_info *hi ) { FILE *imfile ; int length , skip , swap=0 , gg ; char orients[8] , str[8] ; int nx , ny , bpp , cflag , hdroff , stamp=0 , iarg=1 ; float uv17 = -1.0; if( hi == NULL ) return ; /* bad */ hi->good = 0 ; /* not good yet */ if( pathname == NULL || pathname[0] == '\0' ) return ; /* bad */ length = THD_filesize( pathname ) ; if( length < 1024 ) return ; /* bad */ imfile = fopen( pathname , "r" ) ; if( imfile == NULL ) return ; /* bad */ strcpy(str,"JUNK") ; /* initialize string */ fread(str,1,4,imfile) ; /* check for "IMGF" at start of file */ if( str[0]!='I' || str[1]!='M' || str[2]!='G' || str[3]!='F' ){ /* bad */ fclose(imfile) ; return ; } /*-- read next 5 ints (after the "IMGF" string) --*/ fread( &skip , 4,1, imfile ) ; /* offset into file of image data */ fread( &nx , 4,1, imfile ) ; /* x-size */ fread( &ny , 4,1, imfile ) ; /* y-size */ fread( &bpp , 4,1, imfile ) ; /* bits per pixel (should be 16) */ fread( &cflag, 4,1, imfile ) ; /* compression flag (1=uncompressed)*/ /*-- check if nx is funny --*/ if( nx < 0 || nx > 8192 ){ /* have to byte swap these 5 ints */ swap = 1 ; /* flag to swap data, too */ swap_4(&skip); swap_4(&nx); swap_4(&ny); swap_4(&bpp); swap_4(&cflag); } else { swap = 0 ; /* data is ordered for this CPU */ } if( nx < 0 || nx > 8192 || ny < 0 || ny > 8192 ){ /* bad */ fclose(imfile) ; return ; } hi->nx = nx ; hi->ny = ny ; if( skip+2*nx*ny > length || /* file is too short */ skip <= 0 || /* bizarre */ cflag != 1 || /* data is compressed */ bpp != 16 ) return ; /* data is not shorts */ /*-- try to read image header data as well --*/ fseek( imfile , 148L , SEEK_SET ) ; /* magic GEMS offset */ fread( &hdroff , 4,1 , imfile ) ; /* location of image header */ if( swap ) swap_4(&hdroff) ; if( hdroff > 0 && hdroff+256 < length ){ /* can read from image header */ float dx,dy,dz, xyz[9], zz, tr ; int itr, ii,jj,kk ; /*-- get voxel grid sizes --*/ fseek( imfile , hdroff+26 , SEEK_SET ) ; /* dz */ fread( &dz , 4,1 , imfile ) ; fseek( imfile , hdroff+50 , SEEK_SET ) ; /* dx and dy */ fread( &dx , 4,1 , imfile ) ; fread( &dy , 4,1 , imfile ) ; if( swap ){ swap_4(&dx); swap_4(&dy); swap_4(&dz); } hi->dx = dx ; hi->dy = dy ; hi->dz = dz ; /* grid orientation: from 3 sets of LPI corner coordinates: */ /* xyz[0..2] = top left hand corner of image (TLHC) */ /* xyz[3..5] = top right hand corner of image (TRHC) */ /* xyz[6..8] = bottom right hand corner of image (BRHC) */ /* GEMS coordinate orientation here is LPI */ fseek( imfile , hdroff+154 , SEEK_SET ) ; /* another magic number */ fread( xyz , 4,9 , imfile ) ; if( swap ){ swap_4(xyz+0); swap_4(xyz+1); swap_4(xyz+2); swap_4(xyz+3); swap_4(xyz+4); swap_4(xyz+5); swap_4(xyz+6); swap_4(xyz+7); swap_4(xyz+8); } /* x-axis orientation */ /* ii determines which spatial direction is x-axis */ /* and is the direction that has the biggest change */ /* between the TLHC and TRHC */ dx = fabs(xyz[3]-xyz[0]) ; ii = 1 ; dy = fabs(xyz[4]-xyz[1]) ; if( dy > dx ){ ii=2; dx=dy; } dz = fabs(xyz[5]-xyz[2]) ; if( dz > dx ){ ii=3; } dx = xyz[ii+2]-xyz[ii-1] ; if( dx < 0. ){ ii = -ii; } switch( ii ){ case 1: orients[0]= 'L'; orients[1]= 'R'; break; /* Left to Right */ case -1: orients[0]= 'R'; orients[1]= 'L'; break; /* Right to Left */ case 2: orients[0]= 'P'; orients[1]= 'A'; break; /* Posterior to Anterior */ case -2: orients[0]= 'A'; orients[1]= 'P'; break; /* Anterior to Posterior */ case 3: orients[0]= 'I'; orients[1]= 'S'; break; /* Inferior to Superior */ case -3: orients[0]= 'S'; orients[1]= 'I'; break; /* Superior to Inferior */ default: orients[0]='\0'; orients[1]='\0'; break; /* should never happen */ } /* y-axis orientation */ /* jj determines which spatial direction is y-axis */ /* and is the direction that has the biggest change */ /* between the BRHC and TRHC */ dx = fabs(xyz[6]-xyz[3]) ; jj = 1 ; dy = fabs(xyz[7]-xyz[4]) ; if( dy > dx ){ jj=2; dx=dy; } dz = fabs(xyz[8]-xyz[5]) ; if( dz > dx ){ jj=3; } dx = xyz[jj+5]-xyz[jj+2] ; if( dx < 0. ){ jj = -jj; } switch( jj ){ case 1: orients[2] = 'L'; orients[3] = 'R'; break; case -1: orients[2] = 'R'; orients[3] = 'L'; break; case 2: orients[2] = 'P'; orients[3] = 'A'; break; case -2: orients[2] = 'A'; orients[3] = 'P'; break; case 3: orients[2] = 'I'; orients[3] = 'S'; break; case -3: orients[2] = 'S'; orients[3] = 'I'; break; default: orients[2] ='\0'; orients[3] ='\0'; break; } orients[4] = '\0' ; /* terminate orientation string */ kk = 6 - abs(ii)-abs(jj) ; /* which spatial direction is z-axis */ /* where 1=LR, 2=PA, 3=IS */ /* (can't tell orientation from 1 slice) */ zz = xyz[kk-1] ; /* z-coordinate of this slice */ hi->zoff = zz ; strcpy(hi->orients,orients) ; /*-- get TR in seconds --*/ fseek( imfile , hdroff+194 , SEEK_SET ) ; fread( &itr , 4,1 , imfile ) ; /* note itr is an int */ if( swap ) swap_4(&itr) ; hi->tr = 1.0e-6 * itr ; /* itr is in microsec */ /*-- get TE in milliseconds --*/ fseek( imfile , hdroff+202 , SEEK_SET ) ; fread( &itr , 4,1 , imfile ) ; /* itr is an int, in microsec */ if( swap ) swap_4(&itr) ; hi->te = 1.0e-6 * itr ; /* zmodify: get User Variable 17, a likely indicator of a new scan, info by S.Marrett, location from S. Inati's matlab function GE_readHeaderImage.m*/ /* printf ("\nuv17 = \n"); */ fseek ( imfile , hdroff+272+202, SEEK_SET ) ; fread( &uv17 , 4, 1 , imfile ) ; if( swap ) swap_4(&uv17) ; /* printf ("%d ", (int)uv17); */ hi->uv17 = (int)uv17; /* printf ("\n"); */ hi->good = 1 ; /* this is a good file */ } /* end of actually reading image header */ fclose(imfile) ; return ; }