Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

Ifile.c

Go to the documentation of this file.
00001 /**********************************************************************
00002   Program to read GE RT-EPI image files and divine their ordering
00003   in time and space.  To compile on Linux or other sane systems:
00004 
00005     cc -o Ifile -O2 Ifile.c -lm
00006 
00007   If on a Solaris machine, try
00008 
00009     cc -o Ifile -O2 Ifile.c -lm -DSOLARIS_DIRENT_ZERO
00010 ***********************************************************************/
00011 
00012 #include <unistd.h>
00013 #include <stdlib.h>
00014 #include <stdio.h>
00015 #include <string.h>
00016 #include <errno.h>
00017 #include <ctype.h>
00018 #include <sys/types.h>
00019 #include <sys/stat.h>
00020 #include <time.h>
00021 #include <math.h>
00022 
00023 /*------- prototypes [stuff included here from mrilib] -------*/
00024 
00025 time_t THD_file_mtime( char * pathname ) ;
00026 int THD_is_file( char * pathname ) ;
00027 int THD_is_symlink( char * pathname ) ;
00028 long THD_filesize( char * pathname ) ;
00029 int THD_is_directory( char * pathname ) ;
00030 int THD_is_executable( char * pathname ) ;
00031 
00032 void MCW_file_expand( int nin , char ** fin , int * nout , char *** fout ) ;
00033 void MCW_free_expand( int gnum , char ** gout ) ;
00034 void MCW_warn_expand( int www ) ;
00035 void NIH_glob( char *fn , int *nout , char ***fout ) ;
00036 void NIH_glob_free( int gnum , char **gout ) ;
00037 
00038 /*------- typedefs -------*/
00039 
00040 typedef struct {                    /* stuff extracted from GE I.* image */
00041   int good  ;                       /* is this a good image? */
00042   int nx,ny ;                       /* image matrix */
00043   int uv17;                         /* apparently codes for scan index */
00044   float dx,dy,dz , zoff , tr,te ;   /* various dimensions */
00045   char orients[8] ;                 /* orientation string */
00046 } ge_header_info ;
00047 
00048 void ge_header( char *pathname , ge_header_info *hi ) ;
00049 void Ifile_help ();
00050 
00051 /*#define DBG_FILE*/
00052 /***************************************************************************/
00053 
00054 int main( int argc , char *argv[] )
00055 {
00056    int num_I , ii,jj , ngood , nrun , i, UseUv17 = 0;
00057    char **nam_I  ;
00058    char **gnam_I , *PatOpt=NULL, *OutDir = NULL;
00059    int   *time_I , *uv17, lmax=0 , ll , thresh , ibot,itop ;
00060    float *zoff_I , tr , zth1,zth2 , zd ;
00061    ge_header_info geh ;
00062    int Ni, CurVolInd, *New_Vol_Loc, *VolSize, N_Vols, *TroubVolume, iTroub, 
00063       MultiSliceVol, *DupSlice, iDup, BadRun, AllGood = 1, GoodRun, kar = -1,
00064       brk = 0, StrtFiles = 0;
00065    float *Dzv, fact;
00066    char fmt[128] ;
00067    FILE * fout_dbg, *fout_panga;
00068 
00069    if (argc == 1) { Ifile_help(); exit(1); }
00070    kar = 1;
00071         brk = 0;
00072    StrtFiles = 0;
00073         UseUv17 = 0;
00074    while (kar < argc && !StrtFiles) { /* loop accross command ine options */
00075       if (strcmp (argv[kar],"-h") == 0 || strcmp (argv[kar],"-help") == 0) { Ifile_help(); exit(1); }
00076       
00077       if (!brk && (strcmp(argv[kar], "-nt") == 0)) {
00078          UseUv17 = 1;
00079                         brk = 1;
00080          ++kar;
00081                 }
00082       
00083       if (!brk && (strcmp(argv[kar], "-od") == 0)) {
00084          kar ++;
00085                         if (kar >= argc)  {
00086                                 fprintf (stderr, "Error: Need argument after -od.\n");
00087                                 exit (1);
00088                         }
00089          OutDir =  (char *)malloc((strlen(argv[kar])+1)*sizeof(char));
00090          
00091          sprintf(OutDir,"%s",argv[kar]);
00092          brk = 1;
00093          ++kar;
00094       }
00095       
00096       if (!brk && (strcmp(argv[kar], "-sp") == 0)) {
00097          kar ++;
00098                         if (kar >= argc)  {
00099                                 fprintf (stderr, "Error: Need argument after -sp.\n");
00100                                 exit (1);
00101                         }
00102          PatOpt =  (char *)malloc((strlen(argv[kar])+1)*sizeof(char));
00103          
00104          sprintf(PatOpt,"%s",argv[kar]);
00105          brk = 1;
00106          ++kar;
00107       }
00108       
00109       /* nothing found, save location and get out */
00110       if (!brk) {
00111          /* Done with options */
00112          StrtFiles = kar;
00113       } else {
00114          brk = 0;
00115       }
00116    }
00117    
00118    if (UseUv17) { 
00119       fprintf(stderr,"++ using User Variable 17.\n"); } 
00120    else { 
00121       fprintf(stderr,"++ using time stamp.\n");} 
00122    
00123    if (!PatOpt) { 
00124       PatOpt = (char *)malloc(sizeof(char)*10);
00125       sprintf(PatOpt,"alt+z");
00126    }
00127    
00128    if (!OutDir) {
00129       OutDir = (char *)malloc(sizeof(char)*10);
00130       sprintf(OutDir,"afni");
00131    }
00132    
00133    fprintf(stderr,"++ using slice pattern %s\n", PatOpt);
00134    fprintf(stderr,"++ using output directory %s\n", OutDir);
00135    
00136    /*
00137    for (i = 1; i < argc; ++i) {
00138    fprintf(stdout, "%s\n", argv[i]);}
00139    */
00140    fout_panga = fopen("GERT_Reco","w");
00141    if (fout_panga == NULL) { 
00142       fprintf(stderr,"Could not open AutoPanga for writing. Check write permissions.\n");
00143       exit(1);
00144    }
00145    fprintf(fout_panga, "#!/bin/csh -f\n");
00146    fprintf(fout_panga, "#This script was automatically generated by Ifile.\n");
00147    fprintf(fout_panga, "#Change the following options to your liking (see @RenamePanga -help for more info):\n\n");
00148    fprintf(fout_panga, "set OutlierCheck = '-oc' #set to '-oc' to check for outliers, '' to skip checking.\n");
00149    fprintf(fout_panga, "set OutPrefix = 'OutBrick' #Output brick prefix.\n\n");
00150    
00151    /*-- get the list of files */
00152    fprintf(stderr,"++ Expanding file list ...\n") ;
00153    MCW_file_expand( argc - StrtFiles, argv + StrtFiles  , &num_I , &nam_I );
00154 
00155    fprintf(stderr,"++ found %d '*/I.*' files\n",num_I) ;
00156 
00157    if( num_I <= 0 ) exit(1) ;
00158 
00159    /*-- get time and z-offset of each good image --*/
00160 
00161    time_I = (int *)   calloc( sizeof(int)    , num_I ) ;
00162    zoff_I = (float *) calloc( sizeof(float)  , num_I ) ;
00163    gnam_I = (char **) calloc( sizeof(char *) , num_I ) ;
00164    uv17 = (int *) calloc( sizeof(int)    , num_I ) ;
00165    ngood  = 0 ;
00166 
00167    fprintf(stderr,"++ Scanning GE headers") ;
00168    #ifdef DBG_FILE   
00169       fout_dbg = fopen("DBG_IfileOut.txt","w");
00170    #endif
00171    
00172    for( ii=0 ; ii < num_I ; ii++ ){
00173       ge_header( nam_I[ii] , &geh ) ;    /* read GE header */
00174 
00175       if( ii%1000==999 ) fprintf(stderr,".") ;
00176 
00177       if( geh.good ){                    /* is good image file */
00178          zoff_I[ngood] = geh.zoff ;
00179          time_I[ngood] = (int) THD_file_mtime( nam_I[ii] ) ;
00180          gnam_I[ngood] = strdup( nam_I[ii] ) ;
00181          uv17[ngood] = geh.uv17;
00182          
00183          ngood++ ;
00184 
00185          ll = strlen(nam_I[ii]) ; if( ll > lmax ) lmax = ll ;
00186 
00187          tr += geh.tr ;
00188       }
00189       else {
00190       fprintf(stderr,"\tFile %s: !geh.good.\t", nam_I[ii] ) ;
00191       }
00192       #ifdef DBG_FILE   
00193          fprintf(fout_dbg,"%s %d\n", nam_I[ii], time_I[ii]);
00194       #endif
00195    }
00196    
00197   
00198    fprintf(stderr,"\n++ %d files are good images\n",ngood) ;
00199 
00200    MCW_free_expand(  num_I, nam_I ) ;/* don't need nam_I any more */
00201 
00202 
00203    if( ngood < 3 ) exit(1) ;
00204 
00205    /*-- convert to time difference from previous image --*/
00206 
00207    for( ii=ngood-1 ; ii > 0 ; ii-- ) {
00208         time_I[ii] -= time_I[ii-1] ;
00209       
00210       }
00211    time_I[0] = 0 ;
00212 
00213    /*-- set threshold for time, to find distinct imaging runs --*/
00214 
00215    tr    /= ngood ;                 /* average TR reported */
00216    thresh = (int)( 3.0*tr+10.5 ) ;  /* threshold (may need some work) */
00217 
00218    if (UseUv17 == 0) {
00219       /* Just suppress time threshold output, time calculations are not trimmed since they are performed very quickly*/
00220       fprintf(stderr,"++ File time threshold = %d s\n",thresh) ;
00221    }
00222    
00223    /*-- find time steps longer than thresh:
00224         these are starts of new imaging runs 
00225         or with -nt option, use User Variable 17--*/
00226    GoodRun = 0;
00227    nrun = 0 ;
00228    ibot = 0 ;
00229    while( ibot < ngood ){  /* scan forward from ibot */
00230 
00231       /* scan itop until end, or until time step is too big */
00232 
00233       if (UseUv17) {
00234          for( itop=ibot+1; itop<ngood && uv17[itop]==uv17[ibot]; itop++ ) {/* printf("%d ", uv17[itop]); */}; 
00235       } else { /* use time stamp */
00236          for( itop=ibot+1; itop<ngood && time_I[itop]<thresh; itop++ ) ; /* nada */
00237       }
00238       
00239       
00240       /* this run is from ibot to itop-1 */
00241       
00242       
00243       if( ibot == itop-1 ){                    /* skip single files */
00244 
00245          printf("skip:   %s\n",gnam_I[ibot]) ;
00246 
00247       } else {                                 /* more than 1 file */
00248                
00249          nrun++ ;
00250          BadRun = 0; /* Initialize with good faith */
00251          printf("\nRUN %02d:\t  %s .. %s\t",nrun,gnam_I[ibot],gnam_I[itop-1]) ;
00252          /* check for skipped slices [assume 1st 2 slices are OK] */
00253          
00254          if (0) /* intial method */
00255             {/* [[ this algorithm could use some thought!  ]] */
00256             /* [[ maybe compute median delta-zoff?        ]] */
00257             /* [[ what about 1 or 2 slice imaging runs?   ]] */
00258             /* [[ what about slice missing at top or bot? ]] */
00259 
00260             zth1 = fabs( zoff_I[ibot+1] - zoff_I[ibot] ) * 1.01 + 0.01 ;
00261             zth2 = 3.01*zth1 ;
00262 
00263             for( jj=ibot ; jj < itop-1 ; jj++ ){
00264                zd = fabs( zoff_I[jj+1] - zoff_I[jj] ) ;
00265                if( zd > zth1 && zd < zth2 )
00266                   printf("  image %s seems out of place\n",gnam_I[jj+1]) ;
00267             }
00268             }
00269          else
00270             {
00271                               
00272                Ni = itop - ibot; /*Number of images in run, itop is not included*/
00273                Dzv = (float *) calloc( sizeof(float)  , Ni) ;
00274                New_Vol_Loc = (int *) calloc(sizeof(int), Ni); /* could not be bigger than Ni */
00275                VolSize = (int *) calloc(sizeof(int), Ni); 
00276                TroubVolume = (int *) calloc(sizeof(int), Ni); 
00277                DupSlice = (int *) calloc(sizeof(int), Ni); 
00278                
00279                Dzv[0] = 0; /* derivative of volume */
00280                Dzv[1] = zoff_I[ibot+1] - zoff_I[ibot]; 
00281                if (Dzv[1] < 0) 
00282                   {
00283                      fact = -1; 
00284                      Dzv[1] *= fact;
00285                   }
00286                else fact = 1;
00287                if (Dzv[1] != 0) 
00288                   MultiSliceVol = 1; 
00289                else
00290                   MultiSliceVol = 0;
00291                   
00292                
00293                /* find total number of volumes */
00294                iDup = 0;
00295                iTroub = 0;
00296                CurVolInd = 0; /* Current Volume Index */
00297                New_Vol_Loc[CurVolInd] = ibot; /* New Volume Location in series */
00298                for (jj = ibot+2 ; jj < itop ; jj++ ){
00299                   Dzv[jj-ibot] = fact * (zoff_I[jj] - zoff_I[jj - 1]);
00300                   #ifdef DBG_FILE
00301                      fprintf(fout_dbg,"Dzv %f \n", Dzv[jj-ibot]);
00302                    #endif
00303                   if (MultiSliceVol && !Dzv[jj-ibot]) {
00304                      DupSlice[iDup] = jj;
00305                      ++iDup;
00306                   }
00307                   
00308                   if (Dzv[jj-ibot] < 0) { /* New Volume, coming Up */
00309                      ++CurVolInd;
00310                      New_Vol_Loc[CurVolInd] = jj;
00311                      VolSize[CurVolInd-1] = New_Vol_Loc[CurVolInd] - New_Vol_Loc[CurVolInd-1]; 
00312                      if (CurVolInd > 1) { /* compare to first volume */
00313                         if (VolSize[CurVolInd-1] != VolSize[0]) { /* trouble volume */
00314                            TroubVolume[iTroub] = CurVolInd - 1;
00315                            ++iTroub;
00316                         }
00317                      }
00318                   }
00319                } /* jj */
00320                VolSize[CurVolInd] = itop - New_Vol_Loc[CurVolInd]; /* last volume size */
00321                if (VolSize[CurVolInd] != VolSize[0]) { 
00322                   TroubVolume[iTroub] = CurVolInd;
00323                   ++iTroub;
00324                }
00325                N_Vols = CurVolInd+1;
00326                printf("%d images %d Volume(s) \n", Ni, N_Vols);
00327                /* DoppelChecker */
00328                if (N_Vols > 1) {
00329                   /*
00330                   for (i=0; i< N_Vols -1; i++) {
00331                   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]);
00332                   }
00333                   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]); 
00334                   */
00335                }
00336                else {                     
00337                   /* fprintf(stderr, "One volume found: %d slices, Begin %s End %s\n", VolSize[0], gnam_I[New_Vol_Loc[0]],gnam_I[itop-1]); */
00338                }
00339                if (iTroub > 0) { /* Trouble volumes found */
00340                   BadRun = 1;
00341                   fprintf(stderr, "\t\33[1m***************** PANGA! Trouble volumes found. *****************\33[0m\n");
00342                   fprintf(stderr, "\tVol %d %s--%s (%d slices) has a different size from the first volume (%d slices) in the series.\n", \
00343                      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]);
00344                   if (iTroub > 1)
00345                      fprintf(stderr, "\t%d other volumes suffer of similar ailments! Think of the children!\n", iTroub - 1);
00346                   /* Too much info
00347                   for (i=0; i < iTroub; i++) {
00348                      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]);
00349                   }
00350                   */
00351                }
00352                if (iDup > 0) { /* Duplicate slices found */
00353                   BadRun = 1;
00354                   fprintf(stderr, "\t\33[1m***************** PANGA! Dupilcated slices found. *****************\33[0m\n");
00355                   for (i=0; i < iDup; i++) {
00356                      fprintf(stderr, "\tSlice %s appears to be a duplicate of slice %s.\n", gnam_I[DupSlice[i]], gnam_I[DupSlice[i]-1]);
00357                   }                  
00358                } /* iDup > 0 */
00359             }/* New Method */
00360             
00361             if (!BadRun) { /* write out results as a command line for @RenamePanga */
00362                ++ GoodRun;
00363                fprintf(fout_panga,"@RenamePanga %s ", strtok(gnam_I[ibot],"/"));
00364                if (MultiSliceVol)
00365                   fprintf(fout_panga,"%s %d %d $OutPrefix -sp %s $OutlierCheck -od %s\n", 
00366                      strtok(NULL,"/I."), (int)Ni/N_Vols, N_Vols, PatOpt, OutDir);
00367                else
00368                   fprintf(fout_panga,"%s %d %d $OutPrefix -sp %s $OutlierCheck -od %s\n", 
00369                      strtok(NULL,"/I."), N_Vols, (int)Ni/N_Vols, PatOpt, OutDir);
00370             }
00371             else
00372             {
00373                AllGood = 0;
00374             }
00375             free(Dzv);
00376             free(New_Vol_Loc);
00377             free(VolSize);
00378             free(TroubVolume);
00379             free(DupSlice);
00380       }
00381 
00382       ibot = itop ;  /* start scan here */
00383    }
00384    
00385    free(PatOpt);
00386    free(OutDir);
00387    
00388    #ifdef DBG_FILE
00389       fclose (fout_dbg);
00390    #endif
00391    fprintf(fout_panga, "\n");
00392    fclose (fout_panga);
00393    system ("chmod u+x GERT_Reco");
00394 #if 0
00395    /* old code to print out stuff to check if program was working */
00396    sprintf(fmt,"%%-%d.%ds: dt=%%d  zoff=%%g\n",lmax,lmax) ;
00397    for( ii=0 ; ii < ngood ; ii++ )
00398       printf(fmt,gnam_I[ii],time_I[ii],zoff_I[ii]) ;
00399 #endif
00400 
00401    if (!GoodRun) 
00402       system ("rm -f GERT_Reco"); 
00403    else
00404       fprintf(stdout,"\nFound %d complete scans.\nRun\33[1m GERT_Reco \33[0mto create AFNI bricks.\n\n", GoodRun);
00405       
00406    if (AllGood)
00407       exit(0) ;
00408    else
00409       exit(1);
00410 }
00411 
00412 /***************************************************************************/
00413 void Ifile_help ()
00414    {
00415       fprintf(stdout,"\nUsage: Ifile [Options] <File List> \n");
00416       
00417       fprintf(stdout,"\n\t[-nt]: Do not use time stamp to identify complete scans.\n");
00418       fprintf(stdout,"\t       Complete scans are identified from 'User Variable 17'\n"
00419                      "\t       in the image header.\n");
00420       fprintf(stdout,"\t[-sp Pattern]: Slice acquisition pattern.\n"          
00421                      "\t               Sets the slice acquisition pattern.\n"
00422                      "\t               The default option is alt+z.\n"
00423                      "\t               See to3d -help for acceptable options.\n"); 
00424       fprintf(stdout,"\t[-od Output_Directory]: Set the output directory in @RenamePanga.\n"
00425                      "\t                        The default is afni .\n"); 
00426       fprintf(stdout,"\n\t<File List>: Strings of wildcards defining series of\n");
00427       fprintf(stdout,"\t              GE-Real Time (GERT) images to be assembled\n");
00428       fprintf(stdout,"\t              as an afni brick. Example:\n");
00429       fprintf(stdout,"\t              Ifile '*/I.*'\n");
00430       fprintf(stdout,"\t          or  Ifile '083/I.*' '103/I.*' '123/I.*' '143/I.*'\n\n"); 
00431       fprintf(stdout,"\tThe program attempts to identify complete scans from the list\n");
00432       fprintf(stdout,"\tof images supplied on command line and generates the commands\n");
00433       fprintf(stdout,"\tnecessary to turn them into AFNI bricks using the script @RenamePanga.\n");
00434       fprintf(stdout,"\tIf at least one complete scan is identified, a script file named GERT_Reco\n");
00435       fprintf(stdout,"\tis created and executing it creates the afni bricks placed in the afni directory.\n");
00436       fprintf(stdout,"\nHow does it work?\n");
00437       fprintf(stdout,"\tWith the -nt option: Ifile uses the variable 'User Variable 17' in the \n");
00438       fprintf(stdout,"\tI file's header. This option appears to be augmented each time a new\n");
00439       fprintf(stdout,"\tscan is started. (Thanks to S. Marrett for discovering the elusive variable.)\n");
00440       fprintf(stdout,"\tWithout -nt option: Ifile first examines the modification time for each image and \n");
00441       fprintf(stdout,"\tinfers from that which images form a single scan. Consecutive images that are less \n");
00442       fprintf(stdout,"\tthan T seconds apart belong to the same scan. T is set based on the mean\n");
00443       fprintf(stdout,"\ttime delay difference between successive images. The threshold currently\n");
00444       fprintf(stdout,"\tused works for the test data that we have. If it fails for your data, let us\n");
00445       fprintf(stdout,"\tknow and supply us with the data. Once a set of images is grouped into a \n");
00446       fprintf(stdout,"\tscan the sequence of slice location is analysed and duplicate, missing slices,\n");
00447       fprintf(stdout,"\tand incomplete volumes are detected. Sets of images that do not pass these tests\n");
00448       fprintf(stdout,"\tare ignored.\n");
00449       fprintf(stdout,"\nPreserving Time Info: (not necessary with -nt option but does not hurt to preserve anyway)\n");
00450       fprintf(stdout,"\tIt is important to preserve the file modification time info as you copy or untar\n");
00451       fprintf(stdout,"\tthe data. If you neglect to do so and fail to write down where each scan ends\n");
00452       fprintf(stdout,"\tand/or begins, you might have a hell of a time reconstructing your data.\n");
00453       fprintf(stdout,"\tWhen copying image directories, use \33[1m cp -rp ???/* \33[0m and when untaring \n");
00454       fprintf(stdout,"\tthe archive, use \33[1m tar --atime-preserve -xf Archive.tar \33[0m on linux.\n");
00455       fprintf(stdout,"\tOn Sun and SGI, tar -xf Archive.tar preserves the time info.\n"); 
00456       fprintf(stdout,"\nFuture Improvements:\n");
00457       fprintf(stdout,"\tOut of justifiable laziness, and for other less convincing reasons, I have left \n");
00458       fprintf(stdout,"\tIfile and @RenamePanga separate. They can be combined into one program but it's usage\n");
00459       fprintf(stdout,"\twould become more complicated. At any rate, the user should not notice any difference\n");
00460       fprintf(stdout,"\tsince all they have to do is run the script GERT_reco that is created by Ifile.\n\n"); 
00461       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");
00462       
00463    }
00464 
00465 /*** from thd_filestuff.c ***/
00466 
00467 time_t THD_file_mtime( char * pathname )
00468 {
00469    static struct stat buf ; int ii ;
00470 
00471    if( pathname == NULL ) return 0 ;
00472    ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ;
00473    return buf.st_mtime ;
00474 }
00475 
00476 /*-------------------------------------------*/
00477 
00478 int THD_is_file( char * pathname )
00479 {
00480    static struct stat buf ; int ii ;
00481 
00482    if( pathname == NULL ) return 0 ;
00483    ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ;
00484    ii = (buf.st_mode & S_IFREG) != 0 ; return ii ;
00485 }
00486 
00487 /*-------------------------------------------*/
00488 
00489 int THD_is_symlink( char * pathname )
00490 {
00491    char buf[32] ; int ii ;
00492 
00493    ii = readlink( pathname , buf , 32 ) ;
00494    return (ii > 0) ;
00495 }
00496 
00497 /*-------------------------------------------*/
00498 
00499 long THD_filesize( char * pathname )
00500 {
00501    static struct stat buf ; int ii ;
00502 
00503    if( pathname == NULL ) return -1 ;
00504    ii = stat( pathname , &buf ) ; if( ii != 0 ) return -1 ;
00505    return buf.st_size ;
00506 }
00507 
00508 /*-------------------------------------------*/
00509 
00510 int THD_is_directory( char * pathname )
00511 {
00512    static struct stat buf ; int ii ;
00513 
00514    if( pathname == NULL ) return 0 ;
00515    ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ;
00516    ii = (buf.st_mode & S_IFDIR) != 0 ; return ii ;
00517 }
00518 
00519 /*-------------------------------------------*/
00520 
00521 int THD_is_executable( char * pathname )
00522 {
00523    static struct stat buf ; int ii ;
00524 
00525    if( pathname == NULL ) return 0 ;
00526    ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ;
00527    ii = (buf.st_mode & S_IXOTH) != 0 ; return ii ;
00528 }
00529 
00530 /***************************************************************************/
00531 /*** from mcw_glob.[ch] ***/
00532 /*
00533  * Copyright (c) 1989 The Regents of the University of California.
00534  * All rights reserved.
00535  *
00536  * This code is derived from software contributed to Berkeley by
00537  * Guido van Rossum.
00538  *
00539  * Redistribution and use in source and binary forms, with or without
00540  * modification, are permitted provided that the following conditions
00541  * are met:
00542  * 1. Redistributions of source code must retain the above copyright
00543  *    notice, this list of conditions and the following disclaimer.
00544  * 2. Redistributions in binary form must reproduce the above copyright
00545  *    notice, this list of conditions and the following disclaimer in the
00546  *    documentation and/or other materials provided with the distribution.
00547  * 3. All advertising materials mentioning features or use of this software
00548  *    must display the following acknowledgement:
00549  *   This product includes software developed by the University of
00550  *   California, Berkeley and its contributors.
00551  * 4. Neither the name of the University nor the names of its contributors
00552  *    may be used to endorse or promote products derived from this software
00553  *    without specific prior written permission.
00554  *
00555  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00556  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00557  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00558  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00559  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00560  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00561  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00562  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00563  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00564  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00565  * SUCH DAMAGE.
00566  *
00567  *   @(#)glob.h   5.6 (Berkeley) 4/3/91
00568  */
00569 
00570 typedef struct {
00571    int gl_pathc;      /* count of total paths so far */
00572    int gl_matchc;      /* count of paths matching pattern */
00573    int gl_offs;      /* reserved at beginning of gl_pathv */
00574    int gl_flags;      /* copy of flags parameter to glob() */
00575    int (*gl_errfunc)();   /* copy of errfunc parameter to glob() */
00576    char **gl_pathv;   /* list of paths matching pattern */
00577 } glob_t;
00578 
00579 #define   GLOB_APPEND   0x001   /* append to output from previous call */
00580 #define   GLOB_DOOFFS   0x002   /* use gl_offs */
00581 #define   GLOB_ERR   0x004   /* return on error */
00582 #define   GLOB_MAGCHAR   0x008   /* pattern had globbing characters */
00583 #define   GLOB_MARK   0x010   /* append / to matching directories */
00584 #define   GLOB_NOCHECK   0x020   /* return pattern itself if nothing matches */
00585 #define   GLOB_NOSORT   0x040   /* don't sort */
00586 #define   GLOB_QUOTE   0x080   /* quote special chars with \ */
00587 #define GLOB_NOMAGIC   0x100   /* like GLOB_NOCHECK but only if the pattern
00588              * did not have any magic characters */
00589 #define   GLOB_ALTNOT   0x200   /* use alternate glob character [^ not !] */
00590 
00591 #define   GLOB_NOSPACE   (-1)   /* malloc call failed */
00592 #define   GLOB_ABEND   (-2)   /* unignored error */
00593 
00594 int glob (const char *, int, int (*)(char *, int), glob_t *);
00595 void globfree (glob_t *);
00596 
00597 /*
00598  * Glob: the interface is a superset of the one defined in POSIX 1003.2,
00599  * draft 9.
00600  *
00601  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
00602  *
00603  * Optional extra services, controlled by flags not defined by POSIX:
00604  *
00605  * GLOB_QUOTE:
00606  *   Escaping convention: \ inhibits any special meaning the following
00607  *   character might have (except \ at end of string is retained).
00608  * GLOB_MAGCHAR:
00609  *   Set in gl_flags if pattern contained a globbing character.
00610  * GLOB_ALTNOT:
00611  *   Use ^ instead of ! for "not".
00612  * gl_matchc:
00613  *   Number of matches in the current invocation of glob.
00614  */
00615 
00616 
00617 /** the following were in "sh.h",
00618     but I put them here to get rid of the need for that file -- RWCox **/
00619 
00620 #undef  __P        /* in case already defined elsewhere (by gcc, say)*/
00621 #define __P(a) a
00622 
00623 #define xfree     free
00624 #define xmalloc   malloc
00625 #define xrealloc  realloc
00626 
00627 #ifdef SPARKY
00628 #undef _POSIX_SOURCE
00629 #endif
00630 
00631 #include <sys/types.h>
00632 #include <sys/param.h>
00633 #include <sys/stat.h>
00634 #include <dirent.h>
00635 #include <ctype.h>
00636 typedef void * ptr_t;
00637 
00638 /** don't use sh.h any more **/
00639 
00640 #if 0
00641 #  define Char __Char
00642 #  include "sh.h"
00643 #  undef Char
00644 #  undef QUOTE
00645 #  undef TILDE
00646 #  undef META
00647 #  undef CHAR
00648 #  undef ismeta
00649 #  undef Strchr
00650 #endif
00651 
00652 #ifndef S_ISDIR
00653 #define S_ISDIR(a)   (((a) & S_IFMT) == S_IFDIR)
00654 #endif
00655 
00656 #if !defined(S_ISLNK) && defined(S_IFLNK)
00657 #define S_ISLNK(a)   (((a) & S_IFMT) == S_IFLNK)
00658 #endif
00659 
00660 #if !defined(S_ISLNK) && !defined(lstat)
00661 #define lstat stat
00662 #endif
00663 
00664 typedef unsigned short Char;
00665 
00666 static   int    glob1       __P((Char *, glob_t *, int));
00667 static   int    glob2      __P((Char *, Char *, Char *, glob_t *, int));
00668 static   int    glob3      __P((Char *, Char *, Char *, Char *,
00669                  glob_t *, int));
00670 static   int    globextend   __P((Char *, glob_t *));
00671 static   int    match      __P((Char *, Char *, Char *, int));
00672 #ifndef __clipper__
00673 static   int    compare   __P((const ptr_t, const ptr_t));
00674 #endif
00675 static    DIR   *Opendir   __P((Char *));
00676 #ifdef S_IFLNK
00677 static   int    Lstat      __P((Char *, struct stat *));
00678 #endif
00679 static    Char    *Strchr      __P((Char *, int));
00680 #ifdef DEBUG
00681 static   void    qprintf   __P((Char *));
00682 #endif
00683 
00684 #define   DOLLAR      '$'
00685 #define   DOT      '.'
00686 #define   EOS      '\0'
00687 #define   LBRACKET   '['
00688 #define   NOT      '!'
00689 #define ALTNOT      '^'
00690 #define   QUESTION   '?'
00691 #define   QUOTE      '\\'
00692 #define   RANGE      '-'
00693 #define   RBRACKET   ']'
00694 #define   SEP      '/'
00695 #define   STAR      '*'
00696 #define   TILDE      '~'
00697 #define   UNDERSCORE   '_'
00698 
00699 #define   M_META      0x8000
00700 #define M_PROTECT   0x4000
00701 #define   M_MASK      0xffff
00702 #define   M_ASCII      0x00ff
00703 
00704 #define   CHAR(c)      ((c)&M_ASCII)
00705 #define   META(c)      ((c)|M_META)
00706 #define   M_ALL      META('*')
00707 #define   M_END      META(']')
00708 #define   M_NOT      META('!')
00709 #define   M_ALTNOT   META('^')
00710 #define   M_ONE      META('?')
00711 #define   M_RNG      META('-')
00712 #define   M_SET      META('[')
00713 #define   ismeta(c)   (((c)&M_META) != 0)
00714 
00715 #include "machdep.h"
00716 
00717 #if defined(SOLARIS_DIRENT_ZERO) && !defined(SOLARIS_DIRENT_PATCH)
00718 #  define SOLARIS_DIRENT_PATCH
00719 #endif
00720 
00721 #ifdef SOLARIS_DIRENT_PATCH
00722 struct  dirent {
00723      ino_t            d_ino;
00724      off_t            d_off;
00725      unsigned short        d_reclen;
00726      char             d_name[1];
00727 };
00728 #endif
00729 
00730 /*
00731  * Need to dodge two kernel bugs:
00732  * opendir("") != opendir(".")
00733  * NAMEI_BUG: on plain files trailing slashes are ignored in some kernels.
00734  *            POSIX specifies that they should be ignored in directories.
00735  */
00736 
00737 static DIR *
00738 Opendir(str)
00739     register Char *str;
00740 {
00741     char    buf[MAXPATHLEN];
00742     register char *dc = buf;
00743 
00744     if (!*str)
00745    return (opendir("."));
00746     while ((*dc++ = *str++) != '\0')
00747    continue;
00748     return (opendir(buf));
00749 }
00750 
00751 #ifdef S_IFLNK
00752 static int
00753 Lstat(fn, sb)
00754     register Char *fn;
00755     struct stat *sb;
00756 {
00757     char    buf[MAXPATHLEN];
00758     register char *dc = buf;
00759 
00760     while ((*dc++ = *fn++) != '\0')
00761    continue;
00762 # ifdef NAMEI_BUG
00763     {
00764    int     st;
00765 
00766    st = lstat(buf, sb);
00767    if (*buf)
00768        dc--;
00769    return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st);
00770     }
00771 # else
00772     return (lstat(buf, sb));
00773 # endif   /* NAMEI_BUG */
00774 }
00775 #else
00776 #define Lstat Stat
00777 #endif /* S_IFLNK */
00778 
00779 static int
00780 Stat(fn, sb)
00781     register Char *fn;
00782     struct stat *sb;
00783 {
00784     char    buf[MAXPATHLEN];
00785     register char *dc = buf;
00786 
00787     while ((*dc++ = *fn++) != '\0')
00788    continue;
00789 #ifdef NAMEI_BUG
00790     {
00791    int     st;
00792 
00793    st = stat(buf, sb);
00794    if (*buf)
00795        dc--;
00796    return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st);
00797     }
00798 #else
00799     return (stat(buf, sb));
00800 #endif /* NAMEI_BUG */
00801 }
00802 
00803 static Char *
00804 Strchr(str, ch)
00805     Char *str;
00806     int ch;
00807 {
00808     do
00809    if (*str == ch)
00810        return (str);
00811     while (*str++);
00812     return (NULL);
00813 }
00814 
00815 #ifdef DEBUG
00816 static void
00817 qprintf(s)
00818 Char *s;
00819 {
00820     Char *p;
00821 
00822     for (p = s; *p; p++)
00823    printf("%c", *p & 0xff);
00824     printf("\n");
00825     for (p = s; *p; p++)
00826    printf("%c", *p & M_PROTECT ? '"' : ' ');
00827     printf("\n");
00828     for (p = s; *p; p++)
00829    printf("%c", *p & M_META ? '_' : ' ');
00830     printf("\n");
00831 }
00832 #endif /* DEBUG */
00833 
00834 static int
00835 compare(p, q)
00836     const ptr_t  p, q;
00837 {
00838 #if defined(NLS) && !defined(NOSTRCOLL)
00839     errno = 0;  /* strcoll sets errno, another brain-damage */
00840 
00841     return (strcoll(*(char **) p, *(char **) q));
00842 #else
00843     return (strcmp(*(char **) p, *(char **) q));
00844 #endif /* NLS && !NOSTRCOLL */
00845 }
00846 
00847 /*
00848  * The main glob() routine: compiles the pattern (optionally processing
00849  * quotes), calls glob1() to do the real pattern matching, and finally
00850  * sorts the list (unless unsorted operation is requested).  Returns 0
00851  * if things went well, nonzero if errors occurred.  It is not an error
00852  * to find no matches.
00853  */
00854 int
00855 glob(pattern, flags, errfunc, pglob)
00856     const char *pattern;
00857     int     flags;
00858     int     (*errfunc) __P((char *, int));
00859     glob_t *pglob;
00860 {
00861     int     err, oldpathc;
00862     Char *bufnext, *bufend, *compilebuf, m_not;
00863     const unsigned char *compilepat, *patnext;
00864     int     c, not;
00865     Char patbuf[MAXPATHLEN + 1], *qpatnext;
00866     int     no_match;
00867 
00868     patnext = (unsigned char *) pattern;
00869     if (!(flags & GLOB_APPEND)) {
00870    pglob->gl_pathc = 0;
00871    pglob->gl_pathv = NULL;
00872    if (!(flags & GLOB_DOOFFS))
00873        pglob->gl_offs = 0;
00874     }
00875     pglob->gl_flags = flags & ~GLOB_MAGCHAR;
00876     pglob->gl_errfunc = errfunc;
00877     oldpathc = pglob->gl_pathc;
00878     pglob->gl_matchc = 0;
00879 
00880     if (pglob->gl_flags & GLOB_ALTNOT) {
00881    not = ALTNOT;
00882    m_not = M_ALTNOT;
00883     }
00884     else {
00885    not = NOT;
00886    m_not = M_NOT;
00887     }
00888 
00889     bufnext = patbuf;
00890     bufend = bufnext + MAXPATHLEN;
00891     compilebuf = bufnext;
00892     compilepat = patnext;
00893 
00894     no_match = *patnext == not;
00895     if (no_match)
00896    patnext++;
00897 
00898     if (flags & GLOB_QUOTE) {
00899    /* Protect the quoted characters */
00900    while (bufnext < bufend && (c = *patnext++) != EOS)
00901        if (c == QUOTE) {
00902       if ((c = *patnext++) == EOS) {
00903           c = QUOTE;
00904           --patnext;
00905       }
00906       *bufnext++ = (Char) (c | M_PROTECT);
00907        }
00908        else
00909       *bufnext++ = (Char) c;
00910     }
00911     else
00912    while (bufnext < bufend && (c = *patnext++) != EOS)
00913        *bufnext++ = (Char) c;
00914     *bufnext = EOS;
00915 
00916     bufnext = patbuf;
00917     qpatnext = patbuf;
00918     /* we don't need to check for buffer overflow any more */
00919     while ((c = *qpatnext++) != EOS) {
00920    switch (c) {
00921    case LBRACKET:
00922        c = *qpatnext;
00923        if (c == not)
00924       ++qpatnext;
00925        if (*qpatnext == EOS ||
00926       Strchr(qpatnext + 1, RBRACKET) == NULL) {
00927       *bufnext++ = LBRACKET;
00928       if (c == not)
00929           --qpatnext;
00930       break;
00931        }
00932        pglob->gl_flags |= GLOB_MAGCHAR;
00933        *bufnext++ = M_SET;
00934        if (c == not)
00935       *bufnext++ = m_not;
00936        c = *qpatnext++;
00937        do {
00938       *bufnext++ = CHAR(c);
00939       if (*qpatnext == RANGE &&
00940           (c = qpatnext[1]) != RBRACKET) {
00941           *bufnext++ = M_RNG;
00942           *bufnext++ = CHAR(c);
00943           qpatnext += 2;
00944       }
00945        } while ((c = *qpatnext++) != RBRACKET);
00946        *bufnext++ = M_END;
00947        break;
00948    case QUESTION:
00949        pglob->gl_flags |= GLOB_MAGCHAR;
00950        *bufnext++ = M_ONE;
00951        break;
00952    case STAR:
00953        pglob->gl_flags |= GLOB_MAGCHAR;
00954        /* collapse adjacent stars to one, to avoid
00955         * exponential behavior
00956         */
00957        if (bufnext == patbuf || bufnext[-1] != M_ALL)
00958       *bufnext++ = M_ALL;
00959        break;
00960    default:
00961        *bufnext++ = CHAR(c);
00962        break;
00963    }
00964     }
00965     *bufnext = EOS;
00966 #ifdef DEBUG
00967     qprintf(patbuf);
00968 #endif
00969 
00970     if ((err = glob1(patbuf, pglob, no_match)) != 0)
00971    return (err);
00972 
00973     /*
00974      * If there was no match we are going to append the pattern
00975      * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
00976      * and the pattern did not contain any magic characters
00977      * GLOB_NOMAGIC is there just for compatibility with csh.
00978      */
00979     if (pglob->gl_pathc == oldpathc &&
00980    ((flags & GLOB_NOCHECK) ||
00981     ((flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) {
00982    if (!(flags & GLOB_QUOTE)) {
00983        Char *dp = compilebuf;
00984        const unsigned char *sp = compilepat;
00985 
00986        while ((*dp++ = *sp++) != '\0')
00987       continue;
00988    }
00989    else {
00990        /*
00991         * copy pattern, interpreting quotes; this is slightly different
00992         * than the interpretation of quotes above -- which should prevail?
00993         */
00994        while (*compilepat != EOS) {
00995       if (*compilepat == QUOTE) {
00996           if (*++compilepat == EOS)
00997          --compilepat;
00998       }
00999       *compilebuf++ = (unsigned char) *compilepat++;
01000        }
01001        *compilebuf = EOS;
01002    }
01003    return (globextend(patbuf, pglob));
01004     }
01005     else if (!(flags & GLOB_NOSORT))
01006    qsort((char *) (pglob->gl_pathv + pglob->gl_offs + oldpathc),
01007          pglob->gl_pathc - oldpathc, sizeof(char *),
01008          (int (*) __P((const void *, const void *))) compare);
01009     return (0);
01010 }
01011 
01012 static int
01013 glob1(pattern, pglob, no_match)
01014     Char *pattern;
01015     glob_t *pglob;
01016     int     no_match;
01017 {
01018     Char pathbuf[MAXPATHLEN + 1];
01019 
01020     /*
01021      * a null pathname is invalid -- POSIX 1003.1 sect. 2.4.
01022      */
01023     if (*pattern == EOS)
01024    return (0);
01025     return (glob2(pathbuf, pathbuf, pattern, pglob, no_match));
01026 }
01027 
01028 /*
01029  * functions glob2 and glob3 are mutually recursive; there is one level
01030  * of recursion for each segment in the pattern that contains one or
01031  * more meta characters.
01032  */
01033 static int
01034 glob2(pathbuf, pathend, pattern, pglob, no_match)
01035     Char *pathbuf, *pathend, *pattern;
01036     glob_t *pglob;
01037     int     no_match;
01038 {
01039     struct stat sbuf;
01040     int anymeta;
01041     Char *p, *q;
01042 
01043     /*
01044      * loop over pattern segments until end of pattern or until segment with
01045      * meta character found.
01046      */
01047     anymeta = 0;
01048     for (;;) {
01049    if (*pattern == EOS) {   /* end of pattern? */
01050        *pathend = EOS;
01051 
01052        if (Lstat(pathbuf, &sbuf))
01053       return (0);
01054 
01055        if (((pglob->gl_flags & GLOB_MARK) &&
01056        pathend[-1] != SEP) &&
01057       (S_ISDIR(sbuf.st_mode)
01058 #ifdef S_IFLNK
01059        || (S_ISLNK(sbuf.st_mode) &&
01060            (Stat(pathbuf, &sbuf) == 0) &&
01061            S_ISDIR(sbuf.st_mode))
01062 #endif
01063        )) {
01064       *pathend++ = SEP;
01065       *pathend = EOS;
01066        }
01067        ++pglob->gl_matchc;
01068        return (globextend(pathbuf, pglob));
01069    }
01070 
01071    /* find end of next segment, copy tentatively to pathend */
01072    q = pathend;
01073    p = pattern;
01074    while (*p != EOS && *p != SEP) {
01075        if (ismeta(*p))
01076       anymeta = 1;
01077        *q++ = *p++;
01078    }
01079 
01080    if (!anymeta) {      /* no expansion, do next segment */
01081        pathend = q;
01082        pattern = p;
01083        while (*pattern == SEP)
01084       *pathend++ = *pattern++;
01085    }
01086    else         /* need expansion, recurse */
01087        return (glob3(pathbuf, pathend, pattern, p, pglob, no_match));
01088     }
01089     /* NOTREACHED */
01090 }
01091 
01092 
01093 static int
01094 glob3(pathbuf, pathend, pattern, restpattern, pglob, no_match)
01095     Char *pathbuf, *pathend, *pattern, *restpattern;
01096     glob_t *pglob;
01097     int     no_match;
01098 {
01099     extern int errno;
01100     DIR    *dirp;
01101     struct dirent *dp;
01102     int     err;
01103     Char m_not = (pglob->gl_flags & GLOB_ALTNOT) ? M_ALTNOT : M_NOT;
01104     char cpathbuf[MAXPATHLEN], *ptr;
01105 #ifdef SOLARIS_DIRENT_PATCH
01106     /* declaration of vars used in the solaris-patch */
01107     char dname[255];
01108     int ii;
01109 #endif
01110 
01111     *pathend = EOS;
01112     errno = 0;
01113 
01114     if (!(dirp = Opendir(pathbuf))) {
01115    /* todo: don't call for ENOENT or ENOTDIR? */
01116    for (ptr = cpathbuf; (*ptr++ = (char) *pathbuf++) != EOS;)
01117        continue;
01118    if ((pglob->gl_errfunc && (*pglob->gl_errfunc) (cpathbuf, errno)) ||
01119        (pglob->gl_flags & GLOB_ERR))
01120        return (GLOB_ABEND);
01121    else
01122        return (0);
01123     }
01124 
01125     err = 0;
01126 
01127     /* search directory for matching names */
01128     while ((dp = readdir(dirp)) != NULL) {
01129    register unsigned char *sc;
01130    register Char *dc;
01131 
01132 #ifdef SOLARIS_DIRENT_PATCH
01133    /**********
01134    begin patch
01135    **********/
01136 
01137 #ifndef SOLARIS_DIRENT_ZERO
01138    for (ii = -2 ; dp->d_name[ii] != '\0' ; ++ii) {
01139      dname[ii+2] = dp->d_name[ii];
01140    }
01141         dname[ii+2] = '\0';
01142 #else
01143         strcpy(dname, dp->d_name); /* John Koger, March 1999 */
01144 #endif
01145    /**********
01146    end patch
01147    now use dname for dp->d_name
01148    **********/
01149 
01150    /* initial DOT must be matched literally */
01151    if (dname[0] == DOT && *pattern != DOT)
01152        continue;
01153    for (sc = (unsigned char *) dname, dc = pathend;
01154 #else
01155    if (dp->d_name[0] == DOT && *pattern != DOT)
01156        continue;
01157    for (sc = (unsigned char *) dp->d_name, dc = pathend;
01158 #endif
01159         (*dc++ = *sc++) != '\0';)
01160        continue;
01161    if (match(pathend, pattern, restpattern, (int) m_not) == no_match) {
01162        *pathend = EOS;
01163        continue;
01164    }
01165    err = glob2(pathbuf, --dc, restpattern, pglob, no_match);
01166    if (err)
01167        break;
01168     }
01169     /* todo: check error from readdir? */
01170     (void) closedir(dirp);
01171     return (err);
01172 }
01173 
01174 
01175 /*
01176  * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
01177  * add the new item, and update gl_pathc.
01178  *
01179  * This assumes the BSD realloc, which only copies the block when its size
01180  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
01181  * behavior.
01182  *
01183  * Return 0 if new item added, error code if memory couldn't be allocated.
01184  *
01185  * Invariant of the glob_t structure:
01186  *   Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
01187  *    gl_pathv points to (gl_offs + gl_pathc + 1) items.
01188  */
01189 static int
01190 globextend(path, pglob)
01191     Char *path;
01192     glob_t *pglob;
01193 {
01194     register char **pathv;
01195     register int i;
01196     unsigned int newsize;
01197     char   *copy;
01198     Char *p;
01199 
01200     newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
01201     pathv = (char **) (pglob->gl_pathv ?
01202              xrealloc((ptr_t) pglob->gl_pathv, (size_t) newsize) :
01203              xmalloc((size_t) newsize));
01204     if (pathv == NULL)
01205    return (GLOB_NOSPACE);
01206 
01207     if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
01208    /* first time around -- clear initial gl_offs items */
01209    pathv += pglob->gl_offs;
01210    for (i = pglob->gl_offs; --i >= 0;)
01211        *--pathv = NULL;
01212     }
01213     pglob->gl_pathv = pathv;
01214 
01215     for (p = path; *p++;)
01216    continue;
01217     if ((copy = (char *) xmalloc((size_t) (p - path))) != NULL) {
01218    register char *dc = copy;
01219    register Char *sc = path;
01220 
01221    while ((*dc++ = *sc++) != '\0')
01222        continue;
01223    pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
01224     }
01225     pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
01226     return ((copy == NULL) ? GLOB_NOSPACE : 0);
01227 }
01228 
01229 
01230 /*
01231  * pattern matching function for filenames.  Each occurrence of the *
01232  * pattern causes a recursion level.
01233  */
01234 static  int
01235 match(name, pat, patend, m_not)
01236     register Char *name, *pat, *patend;
01237     int m_not;
01238 {
01239     int ok, negate_range;
01240     Char c, k;
01241 
01242     while (pat < patend) {
01243    c = *pat++;
01244    switch (c & M_MASK) {
01245    case M_ALL:
01246        if (pat == patend)
01247       return (1);
01248        do
01249       if (match(name, pat, patend, m_not))
01250           return (1);
01251        while (*name++ != EOS);
01252        return (0);
01253    case M_ONE:
01254        if (*name++ == EOS)
01255       return (0);
01256        break;
01257    case M_SET:
01258        ok = 0;
01259        if ((k = *name++) == EOS)
01260       return (0);
01261        if ((negate_range = ((*pat & M_MASK) == m_not)) != 0)
01262       ++pat;
01263        while (((c = *pat++) & M_MASK) != M_END) {
01264       if ((*pat & M_MASK) == M_RNG) {
01265           if (c <= k && k <= pat[1])
01266          ok = 1;
01267           pat += 2;
01268       }
01269       else if (c == k)
01270           ok = 1;
01271        }
01272        if (ok == negate_range)
01273       return (0);
01274        break;
01275    default:
01276        k = *name++;
01277        if (k != c)
01278       return (0);
01279        break;
01280    }
01281     }
01282     return (*name == EOS);
01283 }
01284 
01285 /* free allocated data belonging to a glob_t structure */
01286 void
01287 globfree(pglob)
01288     glob_t *pglob;
01289 {
01290     register int i;
01291     register char **pp;
01292 
01293     if (pglob->gl_pathv != NULL) {
01294    pp = pglob->gl_pathv + pglob->gl_offs;
01295    for (i = pglob->gl_pathc; i--; ++pp)
01296        if (*pp)
01297       xfree((ptr_t) *pp), *pp = NULL;
01298    xfree((ptr_t) pglob->gl_pathv), pglob->gl_pathv = NULL;
01299     }
01300 }
01301 
01302 static int warn = 0 ;
01303 void MCW_warn_expand( int www ){ warn = www; return; }
01304 
01305 /*------------------------------------------------------------------------
01306    Routines that allows filename wildcarding to be handled inside
01307    to3d.  The advantage: limitations of shell command line lengths.
01308    29 July 1996:  Incorporated "glob" functions from tcsh-6.05, rather
01309                     than rely on system supplying a library.
01310    30 July 1996:  Extended routine to allow for 3D: type prefixes.
01311    10 Feb  2000:  and for 3A: prefixes.
01312 --------------------------------------------------------------------------*/
01313 
01314 void NIH_glob( char *fn , int *nout , char ***fout )
01315 {
01316    MCW_file_expand( 1 , &fn , nout , fout ) ;
01317 }
01318 
01319 void NIH_glob_free( int gnum , char **gout )
01320 {
01321    MCW_free_expand( gnum , gout ) ;
01322 }
01323 
01324 /*------------------------------------------------------------------------*/
01325 
01326 void MCW_file_expand( int nin , char ** fin , int * nout , char *** fout )
01327 {
01328    glob_t gl ;
01329    int    ii , gnum, gold , ilen ;
01330    char ** gout ;
01331    char *  fn ;
01332    char prefix[4] , fpre[128] , fname[256] ;
01333    int  b1,b2,b3,b4,b5 , ib,ig , lpre ;
01334 
01335    if( nin <= 0 ){ *nout = 0 ; return ; }
01336 
01337    gnum = 0 ;
01338    gout = NULL ;
01339 
01340    for( ii=0 ; ii < nin ; ii++ ){
01341       fn = fin[ii] ;
01342 
01343       ig = 0 ;
01344 
01345       /** look for 3D: prefix **/
01346 
01347       if( strlen(fn) > 9 && fn[0] == '3' && fn[1] == 'D' ){
01348          ib = 0 ;
01349          prefix[ib++] = '3' ;
01350          prefix[ib++] = 'D' ;
01351          if( fn[2] == ':' ){ prefix[ib++] = '\0' ; }
01352          else              { prefix[ib++] = fn[2] ; prefix[ib++] = '\0' ; }
01353 
01354          ig = sscanf( fn+ib , "%d:%d:%d:%d:%d:%s" ,     /* must scan all */
01355                       &b1,&b2,&b3,&b4,&b5 , fname ) ;   /* six items OK  */
01356 
01357          /** if have all 6 3D: items, then make a 3D: prefix for output **/
01358 
01359          if( ig == 6 ){
01360             sprintf(fpre , "%s:%d:%d:%d:%d:%d:" , prefix,b1,b2,b3,b4,b5) ;
01361             lpre = strlen(fpre) ;
01362          } else {
01363             ig = 0 ;
01364          }
01365       }
01366 
01367       if( strlen(fn) > 9 && fn[0] == '3' && fn[1] == 'A' && fn[3] == ':' ){
01368          ib = 0 ;
01369          prefix[ib++] = '3' ;
01370          prefix[ib++] = 'A' ;
01371          prefix[ib++] = fn[2] ;
01372          prefix[ib++] = '\0' ;
01373 
01374          ig = sscanf( fn+ib , "%d:%d:%d:%s" ,  /* must scan all */
01375                       &b1,&b2,&b3, fname ) ;   /* four items OK */
01376 
01377          /** if have all 4 3A: items, then make a 3A: prefix for output **/
01378 
01379          if( ig == 4 ){
01380             sprintf(fpre , "%s:%d:%d:%d:" , prefix,b1,b2,b3) ;
01381             lpre = strlen(fpre) ;
01382          } else {
01383             ig = 0 ;
01384          }
01385       }
01386 
01387       if( ig > 0 ) (void) glob( fname , 0 , NULL ,  &gl ) ;  /* 3D: was OK */
01388       else         (void) glob( fn    , 0 , NULL ,  &gl ) ;  /*     not OK */
01389 
01390       /** put each matched string into the output array **/
01391 
01392       if( gl.gl_pathc > 0 ){
01393 
01394          /** make space for output now **/
01395          gold  = gnum ;
01396          gnum += gl.gl_pathc ;
01397          if( gout == NULL ) gout = (char **) malloc (      sizeof(char *)*gnum);
01398          else               gout = (char **) realloc(gout, sizeof(char *)*gnum);
01399 
01400          for( ib=0 ; ib < gl.gl_pathc ; ib++ ){
01401             ilen = strlen( gl.gl_pathv[ib] ) + 1 ;  /* length of this name */
01402             if( ig > 0 ) ilen += lpre ;             /* plus 3D: prefix?    */
01403 
01404             gout[ib+gold] = (char *) malloc( sizeof(char) * ilen ) ; /* output! */
01405 
01406             if( ig > 0 ){
01407                strcpy( gout[ib+gold] , fpre ) ;             /* 3D: prefix */
01408                strcat( gout[ib+gold] , gl.gl_pathv[ib] ) ;  /* then name  */
01409             }
01410             else {
01411                strcpy( gout[ib+gold] , gl.gl_pathv[ib] ) ;  /* just name */
01412             }
01413          }
01414 
01415       } else if( ig == 6 && strcmp(fname,"ALLZERO") == 0 ){ /* 06 Mar 2001 */
01416 
01417          gold = gnum ; gnum++ ;
01418          if( gout == NULL ) gout = (char **) malloc (      sizeof(char *)*gnum);
01419          else               gout = (char **) realloc(gout, sizeof(char *)*gnum);
01420 
01421          ilen = lpre + strlen(fname) + 1 ;
01422          gout[gold] = (char *) malloc( sizeof(char) * ilen ) ; /* output! */
01423          strcpy( gout[gold] , fpre ) ;
01424          strcat( gout[gold] , fname ) ;
01425 
01426       } else {  /* 30 Apr 2001 */
01427 
01428          if( warn )  /* 13 Jul 2001 - print only if told to do so */
01429            fprintf(stderr,"** Can't find file %s\n", (ig>0) ? fname : fn ) ;
01430       }
01431 
01432       globfree( &gl ) ;
01433    }
01434 
01435    *nout = gnum ; *fout = gout ; return ;
01436 }
01437 
01438 void MCW_free_expand( int gnum , char ** gout )
01439 {
01440    int ii ;
01441 
01442    if( gout == NULL ) return ;
01443 
01444    for( ii=0 ; ii < gnum ; ii++ ) free( gout[ii] ) ;
01445    free( gout ) ;
01446    return ;
01447 }
01448 
01449 /***************************************************************************/
01450 /*** adapted from ge_header.c ***/
01451 
01452 /*---------------------------------------------------------------*/
01453 
01454 static void swap_4(void *ppp)
01455 {
01456    unsigned char *pntr = (unsigned char *) ppp ;
01457    unsigned char b0, b1, b2, b3;
01458 
01459    b0 = *pntr; b1 = *(pntr+1); b2 = *(pntr+2); b3 = *(pntr+3);
01460    *pntr = b3; *(pntr+1) = b2; *(pntr+2) = b1; *(pntr+3) = b0;
01461 }
01462 
01463 /*---------------------------------------------------------------*/
01464 
01465 static void swap_8(void *ppp)
01466 {
01467    unsigned char *pntr = (unsigned char *) ppp ;
01468    unsigned char b0, b1, b2, b3;
01469    unsigned char b4, b5, b6, b7;
01470 
01471    b0 = *pntr    ; b1 = *(pntr+1); b2 = *(pntr+2); b3 = *(pntr+3);
01472    b4 = *(pntr+4); b5 = *(pntr+5); b6 = *(pntr+6); b7 = *(pntr+7);
01473 
01474    *pntr     = b7; *(pntr+1) = b6; *(pntr+2) = b5; *(pntr+3) = b4;
01475    *(pntr+4) = b3; *(pntr+5) = b2; *(pntr+6) = b1; *(pntr+7) = b0;
01476 }
01477 
01478 /*---------------------------------------------------------------*/
01479 
01480 static void swap_2(void *ppp)
01481 {
01482    unsigned char *pntr = (unsigned char *) ppp ;
01483    unsigned char b0, b1;
01484 
01485    b0 = *pntr; b1 = *(pntr+1);
01486    *pntr = b1; *(pntr+1) = b0;
01487 }
01488 
01489 /******************************************************************/
01490 /*** Return info from a GEMS IMGF file into user-supplied struct **/
01491 
01492 void ge_header( char *pathname , ge_header_info *hi )
01493 {
01494    FILE *imfile ;
01495    int  length , skip , swap=0 , gg ;
01496    char orients[8] , str[8] ;
01497    int nx , ny , bpp , cflag , hdroff , stamp=0 , iarg=1 ;
01498    float uv17 = -1.0;
01499    
01500    if( hi == NULL ) return ;            /* bad */
01501    hi->good = 0 ;                       /* not good yet */
01502    if( pathname    == NULL ||
01503        pathname[0] == '\0'   ) return ; /* bad */
01504 
01505    length = THD_filesize( pathname ) ;
01506    if( length < 1024 ) return ;         /* bad */
01507 
01508    imfile = fopen( pathname , "r" ) ;
01509    if( imfile == NULL ) return ;        /* bad */
01510 
01511    strcpy(str,"JUNK") ;     /* initialize string */
01512    fread(str,1,4,imfile) ;  /* check for "IMGF" at start of file */
01513 
01514    if( str[0]!='I' || str[1]!='M' || str[2]!='G' || str[3]!='F' ){ /* bad */
01515       fclose(imfile) ; return ;
01516    }
01517 
01518    /*-- read next 5 ints (after the "IMGF" string) --*/
01519 
01520    fread( &skip , 4,1, imfile ) ; /* offset into file of image data */
01521    fread( &nx   , 4,1, imfile ) ; /* x-size */
01522    fread( &ny   , 4,1, imfile ) ; /* y-size */
01523    fread( &bpp  , 4,1, imfile ) ; /* bits per pixel (should be 16) */
01524    fread( &cflag, 4,1, imfile ) ; /* compression flag (1=uncompressed)*/
01525 
01526    /*-- check if nx is funny --*/
01527 
01528    if( nx < 0 || nx > 8192 ){      /* have to byte swap these 5 ints */
01529      swap = 1 ;                    /* flag to swap data, too */
01530      swap_4(&skip); swap_4(&nx); swap_4(&ny); swap_4(&bpp); swap_4(&cflag);
01531    } else {
01532      swap = 0 ;  /* data is ordered for this CPU */
01533    }
01534    if( nx < 0 || nx > 8192 || ny < 0 || ny > 8192 ){  /* bad */
01535       fclose(imfile) ; return ;
01536    }
01537 
01538    hi->nx = nx ;
01539    hi->ny = ny ;
01540 
01541    if( skip+2*nx*ny >  length ||               /* file is too short */
01542        skip         <= 0      ||               /* bizarre  */
01543        cflag        != 1      ||               /* data is compressed */
01544        bpp          != 16        ) return ;    /* data is not shorts */
01545 
01546    /*-- try to read image header data as well --*/
01547 
01548    fseek( imfile , 148L , SEEK_SET ) ; /* magic GEMS offset */
01549    fread( &hdroff , 4,1 , imfile ) ;   /* location of image header */
01550    if( swap ) swap_4(&hdroff) ;
01551 
01552    if( hdroff > 0 && hdroff+256 < length ){   /* can read from image header */
01553        float dx,dy,dz, xyz[9], zz, tr ; int itr, ii,jj,kk ;
01554 
01555        /*-- get voxel grid sizes --*/
01556 
01557        fseek( imfile , hdroff+26 , SEEK_SET ) ;    /* dz */
01558        fread( &dz , 4,1 , imfile ) ;
01559 
01560        fseek( imfile , hdroff+50 , SEEK_SET ) ;    /* dx and dy */
01561        fread( &dx , 4,1 , imfile ) ;
01562        fread( &dy , 4,1 , imfile ) ;
01563 
01564        if( swap ){ swap_4(&dx); swap_4(&dy); swap_4(&dz); }
01565 
01566        hi->dx = dx ; hi->dy = dy ; hi->dz = dz ;
01567 
01568        /* grid orientation: from 3 sets of LPI corner coordinates: */
01569        /*   xyz[0..2] = top left hand corner of image     (TLHC)   */
01570        /*   xyz[3..5] = top right hand corner of image    (TRHC)   */
01571        /*   xyz[6..8] = bottom right hand corner of image (BRHC)   */
01572        /* GEMS coordinate orientation here is LPI                  */
01573 
01574        fseek( imfile , hdroff+154 , SEEK_SET ) ;  /* another magic number */
01575        fread( xyz , 4,9 , imfile ) ;
01576        if( swap ){
01577           swap_4(xyz+0); swap_4(xyz+1); swap_4(xyz+2);
01578           swap_4(xyz+3); swap_4(xyz+4); swap_4(xyz+5);
01579           swap_4(xyz+6); swap_4(xyz+7); swap_4(xyz+8);
01580        }
01581 
01582        /* x-axis orientation */
01583        /* ii determines which spatial direction is x-axis  */
01584        /* and is the direction that has the biggest change */
01585        /* between the TLHC and TRHC                        */
01586 
01587        dx = fabs(xyz[3]-xyz[0]) ; ii = 1 ;
01588        dy = fabs(xyz[4]-xyz[1]) ; if( dy > dx ){ ii=2; dx=dy; }
01589        dz = fabs(xyz[5]-xyz[2]) ; if( dz > dx ){ ii=3;        }
01590        dx = xyz[ii+2]-xyz[ii-1] ; if( dx < 0. ){ ii = -ii;    }
01591        switch( ii ){
01592         case  1: orients[0]= 'L'; orients[1]= 'R'; break; /* Left      to Right     */
01593         case -1: orients[0]= 'R'; orients[1]= 'L'; break; /* Right     to Left      */
01594         case  2: orients[0]= 'P'; orients[1]= 'A'; break; /* Posterior to Anterior  */
01595         case -2: orients[0]= 'A'; orients[1]= 'P'; break; /* Anterior  to Posterior */
01596         case  3: orients[0]= 'I'; orients[1]= 'S'; break; /* Inferior  to Superior  */
01597         case -3: orients[0]= 'S'; orients[1]= 'I'; break; /* Superior  to Inferior  */
01598         default: orients[0]='\0'; orients[1]='\0'; break; /* should never happen    */
01599        }
01600 
01601        /* y-axis orientation */
01602        /* jj determines which spatial direction is y-axis  */
01603        /* and is the direction that has the biggest change */
01604        /* between the BRHC and TRHC                        */
01605 
01606        dx = fabs(xyz[6]-xyz[3]) ; jj = 1 ;
01607        dy = fabs(xyz[7]-xyz[4]) ; if( dy > dx ){ jj=2; dx=dy; }
01608        dz = fabs(xyz[8]-xyz[5]) ; if( dz > dx ){ jj=3;        }
01609        dx = xyz[jj+5]-xyz[jj+2] ; if( dx < 0. ){ jj = -jj;    }
01610        switch( jj ){
01611          case  1: orients[2] = 'L'; orients[3] = 'R'; break;
01612          case -1: orients[2] = 'R'; orients[3] = 'L'; break;
01613          case  2: orients[2] = 'P'; orients[3] = 'A'; break;
01614          case -2: orients[2] = 'A'; orients[3] = 'P'; break;
01615          case  3: orients[2] = 'I'; orients[3] = 'S'; break;
01616          case -3: orients[2] = 'S'; orients[3] = 'I'; break;
01617          default: orients[2] ='\0'; orients[3] ='\0'; break;
01618        }
01619 
01620        orients[4] = '\0' ;   /* terminate orientation string */
01621 
01622        kk = 6 - abs(ii)-abs(jj) ;   /* which spatial direction is z-axis   */
01623                                     /* where 1=LR, 2=PA, 3=IS               */
01624                                     /* (can't tell orientation from 1 slice) */
01625 
01626        zz = xyz[kk-1] ;             /* z-coordinate of this slice */
01627 
01628        hi->zoff = zz ;
01629        strcpy(hi->orients,orients) ;
01630 
01631        /*-- get TR in seconds --*/
01632 
01633        fseek( imfile , hdroff+194 , SEEK_SET ) ;
01634        fread( &itr , 4,1 , imfile ) ; /* note itr is an int */
01635        if( swap ) swap_4(&itr) ;
01636        hi->tr = 1.0e-6 * itr ;        /* itr is in microsec */
01637 
01638        /*-- get TE in milliseconds --*/
01639 
01640        fseek( imfile , hdroff+202 , SEEK_SET ) ;
01641        fread( &itr , 4,1 , imfile ) ; /* itr is an int, in microsec */
01642        if( swap ) swap_4(&itr) ;
01643        hi->te = 1.0e-6 * itr ;
01644 
01645        /* 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*/
01646          
01647       /* printf ("\nuv17 = \n"); */
01648       fseek ( imfile , hdroff+272+202, SEEK_SET ) ;
01649       fread( &uv17 , 4, 1 , imfile ) ;
01650       if( swap ) swap_4(&uv17) ;
01651       /* printf ("%d ", (int)uv17);  */
01652       hi->uv17 = (int)uv17; 
01653       /* printf ("\n"); */
01654       
01655        hi->good = 1 ;                 /* this is a good file */
01656 
01657    } /* end of actually reading image header */
01658 
01659    fclose(imfile) ; return ;
01660 }
 

Powered by Plone

This site conforms to the following standards: