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  

Imon.c

Go to the documentation of this file.
00001 
00002 #define IFM_VERSION "version 3.3a (March 22, 2005)"
00003 
00004 static char g_history[] =
00005     "----------------------------------------------------------------------\n"
00006     " history:\n"
00007     "\n"
00008     " 1.0  November 21, 2002\n"
00009     "   - initial release\n"
00010     "\n"
00011     " 1.1  November 27, 2002\n"
00012     "   - renamed from Hfile to Imon (I-file monitor)\n"
00013     "\n"
00014     " 1.2  November 27, 2002\n"
00015     "   - after N idle mid-run TRs, print warning message\n"
00016     "   - added '-nice INCR' option\n"
00017     "   - added BEEP on error\n"
00018     "   - replaced '-status' with '-quiet', so '-debug 1' is default\n"
00019     "   - no fatal error during volume search, try to recover\n"
00020     "   - display that the user should use <ctrl-c> to quit\n"
00021     "   - adjust globbing to be '...[0-9][02468]?/I.*'  (or w/[13579])\n"
00022     "\n"
00023     " 1.3  December 13, 2002\n"
00024     "   - compile as standalone (include mcw_glob, but not mcw_malloc)\n"
00025     "   - added l_THD_filesize (local copy of THD_filesize)\n"
00026     "   - removed dependance on mrilib.h and r_idisp.h\n"
00027     "\n"
00028     " 2.0  January 15, 2003\n"
00029     "   - rtfeedme feature\n"
00030     "       o added -rt   option: pass data to afni as collected\n"
00031     "       o added -host option: specify afni host for real-time\n"
00032     "       o added -swap option: byte swap pairs before sending to afni\n"
00033     "       o created realtime.[ch] for all RT processing functions\n"
00034     "       o (see gAC struct and ART_ functions)\n"
00035     "   - actually read and store images (to be sent to afni)\n"
00036     "   - moved function declarations to Imon.c (from Imon.h)\n"
00037     "\n"
00038     " 2.1  January 27, 2003\n"
00039     "   - added '-nt VOLUMES_PER_RUN' option (for checking stalled runs)\n"
00040     "\n"
00041     " 2.2  February 2, 2003\n"
00042     "   - allow IFM_MAX_GE_FAILURES file reading failures\n"
00043     "\n"
00044     " 2.3  February 14, 2003\n"
00045     "   - added -start_file option\n"
00046     "   - created opts_t struct for user options\n"
00047     "\n"
00048     " 2.4  February 18, 2003\n"
00049     "   - added DRIVE_AFNI command to open a graph window\n"
00050     "   - added -drive_afni option\n"
00051     "   - added NOTE command to append Imon command to any new dataset\n"
00052     "\n"
00053     " 2.5  February 20, 2003\n"
00054     "   - deal better with missing first slice of first volume\n"
00055     "   - make each DRIVE_AFNI command separate\n"
00056     "\n"
00057     " 2.6  March 25, 2003\n"
00058     "   - added -GERT_Reco2 option\n"
00059     "   - RT: only send good volumes to afni\n"
00060     "   - RT: added -rev_byte_order option\n"
00061     "   - RT: also open relevant image window\n"
00062     "   - RT: mention starting file in NOTE command\n"
00063     "\n"
00064     " 2.7  June 25, 2003\n"
00065     "   - added axes offsets (see xorg and realtime.c: XYZFIRST)\n"
00066     "\n"
00067     " 2.8  June 27, 2003\n"
00068     "   - BYTEORDER is now operational in plug_realtime\n"
00069     "   - implemented -rev_byte_order option\n"
00070     "\n"
00071     " 2.9  July 27, 2003\n"
00072     "   - wrap unknown printed strings in NULL check\n"
00073     "   - only print newer files in debug check\n"
00074     "\n"
00075     " 2.10 August 5, 2003\n"
00076     "   - added '-sp SLICE_PATTERN' option (see spat and opts.sp)\n"
00077     "\n"
00078     " 2.11 August 14, 2003\n"
00079     "   - added '-quit' option\n"
00080     "   - changed CHECK_NULL_STR() output to (NULL) (to see when used)\n"
00081     "   - change exit status to 0 (why the heck did I use 1?)\n"
00082     "   - allow I.* or i.* filename expansions\n"
00083     "\n"
00084     " 3.0 August 20, 2003\n"
00085     "   - It seems that the GE scanners may write the files for a volume\n"
00086     "     out of order.  To handle that possibility, volume_match() will\n"
00087     "     re-test any volume for error conditions (separated by sleep()).\n"
00088     "     Errors will be reported only if they persist (i.e. the scanner\n"
00089     "     is not still working on the volume).\n"
00090     "\n"
00091     " 3.1 September 02, 2003\n"
00092     "   - Add option '-od OUTPUT_DIRECTORY' for the GERT_Reco2 case.\n"
00093     "\n"
00094     " 3.2 January 13, 2004\n"
00095     "   - added '-zorder ORDER' option to specify slice timing in the\n"
00096     "     real-time mode (the real-time default is now 'alt')\n"
00097     "   - added '-hist' option for history display\n"
00098     "\n"
00099     " 3.3 February 13, 2004\n"
00100     "   - added '-rt_cmd' option for passing commands to the realtime plugin\n"
00101     "       (this option may be used multiple times)\n"
00102     "   - '-drive_cmd' option can now be used multiple times\n"
00103     "   - realtime.c: changed default zorder back to seq\n"
00104     "       (affects slice order in the RT plugin)\n"
00105     "   - realtime.c: passed list of drive and rt commands to RT plugin\n"
00106     "   - added add_to_string_list() and empty_string_list()\n"
00107     "\n"
00108     " 3.3a March 22, 2005 - removed all tabs\n"
00109     " 3.3b May   16, 2005 - incorporate some Dimon changes\n"
00110     " 3.4  July   5, 2005 - removed tabs\n"
00111     "----------------------------------------------------------------------\n";
00112 
00113 /*----------------------------------------------------------------------
00114  * todo:
00115  *
00116  * - add -full_prefix option
00117  *----------------------------------------------------------------------
00118 */
00119 
00120 /*----------------------------------------------------------------------
00121  * Imon - monitor real-time aquisition of I-files
00122  *
00123  *     This program is intended to be run during a scanning session
00124  *     on a GE scanner, to monitor the collection of I-files.  The
00125  *     user will be notified of any missing slice or any slice that
00126  *     is aquired out of order.
00127  *
00128  *     It is recommended that the user runs 'Imon' before scanning
00129  *     begins, and then watches for error messages during the
00130  *     scanning session.  The user should terminate the program
00131  *     whey they are done with all runs.
00132  *
00133  *     At the present time, the user must use <ctrl-c> to terminate
00134  *     the program.
00135  *
00136  *   usage: Imon [options] -start_dir DIR
00137  *
00138  *   examples:    Imon -start_dir 003
00139  *                Imon -help
00140  *                Imon -version
00141  *                Imon -start_dir 003 -GERT_Reco2
00142  *                Imon -start_dir 003 -debug 2
00143  *                Imon -start_dir 003 -nt 120
00144  *                Imon -start_dir 003 -rt -host pickle -swap
00145  *                Imon -start_dir 003 -rt -host pickle -rev_byte_order
00146  *----------------------------------------------------------------------
00147 */
00148 
00149 #include <stdio.h>
00150 #include <ctype.h>
00151 #include <dirent.h>
00152 #include <errno.h>
00153 #include <math.h>
00154 #include <signal.h>
00155 #include <stdlib.h>
00156 #include <string.h>
00157 #include <sys/types.h>
00158 #include <sys/stat.h>
00159 #include <unistd.h>
00160 
00161 #include "Imon.h"
00162 #include "l_mcw_glob.h"
00163 #include "thd_iochan.h"
00164 #include "realtime.h"
00165 
00166 #define IFM_PROG_NAME   "Imon"
00167 
00168 /*----------------------------------------------------------------------*/
00169 /* static function declarations */
00170 
00171 static int add_to_string_list  ( string_list * list, char * str );
00172 static int alloc_x_im          ( im_store_t * is, int bytes );
00173 static int check_error         ( int * retry, float tr, char * note );
00174 static int check_im_byte_order ( int * order, vol_t * v, param_t * p );
00175 static int check_im_store_space( im_store_t * is, int num_images );
00176 static int check_stalled_run   ( int run, int seq_num, int naps, int nap_time );
00177 static int complete_orients_str( vol_t * v, param_t * p );
00178 static int create_gert_script  ( stats_t * s, opts_t * opts );
00179 static int dir_expansion_form  ( char * sin, char ** sexp );
00180 static int empty_string_list   ( string_list * list, int free_mem );
00181 static int find_first_volume   ( vol_t * v, param_t * p, ART_comm * ac );
00182 static int find_fl_file_index  ( param_t * p, char * file );
00183 static int find_more_volumes   ( vol_t * v, param_t * p, ART_comm * ac );
00184 static int find_next_zoff      ( param_t * p, int start, float zoff );
00185 static int init_extras         ( param_t * p, ART_comm * ac );
00186 static int init_options        ( param_t * p, ART_comm * a, int argc,
00187                                  char * argv[] );
00188 static int nap_time_from_tr    ( float tr );
00189 static int path_to_dir_n_suffix( char * dir, char * suff, char * path );
00190 static int read_ge_files       ( param_t * p, int start, int max );
00191 static int read_ge_image       ( char * pathname, finfo_t * fp,
00192                                  int get_image, int need_memory );
00193 static int scan_ge_files       ( param_t * p, int next, int nfiles );
00194 static int set_nice_level      ( int level );
00195 static int set_volume_stats    ( param_t * p, stats_t * s, vol_t * v );
00196 static int show_run_stats      ( stats_t * s );
00197 static int str_char_count      ( char * str, int len, char target );
00198 static int swap_4              ( void * ptr );
00199 
00200 static void hf_signal          ( int signum );
00201 
00202 /* volume scanning */
00203 static int volume_match  ( vol_t * vin, vol_t * vout, param_t * p, int start );
00204 static int volume_search ( vol_t * V, param_t * p, int start, int maxsl,
00205                            int * fl_start );
00206 
00207 /* information functions */
00208 static int idisp_hf_opts_t      ( char * info, opts_t * opt );
00209 static int idisp_hf_param_t     ( char * info, param_t * p );
00210 static int idisp_hf_vol_t       ( char * info, vol_t * v );
00211 static int idisp_ge_extras      ( char * info, ge_extras * E );
00212 static int idisp_ge_header_info ( char * info, ge_header_info * I );
00213 static int idisp_im_store_t     ( char * info, im_store_t * is );
00214 
00215 static int usage                ( char * prog, int level );
00216 
00217 /* local copy of AFNI function */
00218 static unsigned long l_THD_filesize( char * pathname );
00219 
00220 /*----------------------------------------------------------------------*/
00221 
00222 #define MAIN
00223 
00224 /***********************************************************************/
00225 /* globals */
00226 
00227 IFM_debug gD;           /* debug information         */
00228 param_t   gP;           /* main parameter struct     */
00229 stats_t   gS;           /* general run information   */
00230 ART_comm  gAC;          /* afni communication struct */
00231 
00232 /***********************************************************************/
00233 int main( int argc, char * argv[] )
00234 {
00235     ART_comm * ac = &gAC;               /* access AFNI comm as local   */
00236     param_t  * p  = &gP;                /* access the global as local  */
00237     vol_t      baseV;                   /* base volume - first scanned */
00238     int        ret_val;
00239 
00240     /* validate inputs and init options structure */
00241     if ( (ret_val = init_options( p, ac, argc, argv )) != 0 )
00242         return ret_val;
00243 
00244     if ( (ret_val = init_extras( p, ac )) != 0 )
00245         return ret_val;
00246 
00247     if ( (ret_val = find_first_volume( &baseV, p, ac )) != 0 )
00248         return ret_val;
00249 
00250     if ( (ret_val = find_more_volumes( &baseV, p, ac )) != 0 )
00251         return ret_val;
00252 
00253     return 0;
00254 }
00255 /***********************************************************************/
00256 
00257 /*----------------------------------------------------------------------
00258  * find_first_volume:   scan p->flist for a complete volume
00259  *
00260  * This function runs until either a volume is located, or an
00261  * error occurs.
00262  * 
00263  * return:     0 : on success
00264  *          else : error
00265  *----------------------------------------------------------------------
00266 */
00267 static int find_first_volume( vol_t * v, param_t * p, ART_comm * ac )
00268 {
00269     int max_im_alloc = IFM_MAX_IM_ALLOC;
00270     int ret_val;
00271     int fl_start = 0;  /* starting offset into the current flist */
00272 
00273     if ( gD.level > 0 )                 /* status */
00274         fprintf( stderr, "-- scanning for first volume\n" );
00275 
00276     ret_val = 0;
00277     while ( ret_val == 0 )
00278     {
00279         ret_val = read_ge_files( p, fl_start, max_im_alloc );
00280 
00281         if ( ret_val > 0 )
00282         {
00283             ret_val = volume_search( v, p, 0, 0, &fl_start );
00284 
00285             if ( ret_val == -1 )   /* try to recover from a data error */
00286                 ret_val = 0;
00287 
00288             if ( (ret_val == 0) && (p->nused > (max_im_alloc / 2)) )
00289             {
00290                 /* If we don't have a volume yet, but have used "too much"
00291                  * of our available memory, request more, making sure there
00292                  * is enough for a volume, despite the previous max_im_alloc
00293                  * limitation.
00294                  */
00295                 max_im_alloc *= 2;
00296             }
00297         }
00298 
00299         if ( ret_val == 0 )                     /* we are not done yet */
00300         {
00301             if ( gD.level > 0 )                              /* status */
00302                 fprintf( stderr, "." );
00303 
00304             sleep( 4 );                                   /* nap time! */
00305         }
00306         else if ( ret_val > 0 )         /* success - we have a volume! */
00307         {
00308             if ( gD.level > 0 )
00309             {
00310                 fprintf( stderr, "\n-- first volume found\n" );
00311                 if ( gD.level > 1 )
00312                 {
00313                     idisp_hf_vol_t( "first volume : ", v );
00314                     idisp_hf_param_t( "first vol - new params : ", p );
00315                 }
00316             }
00317 
00318             /* make sure there is enough memory for bad volumes */
00319             if ( p->nalloc < (4 * v->nim) )
00320             {
00321                 p->nalloc = 4 * v->nim;
00322                 p->flist = (finfo_t *)realloc( p->flist,
00323                                                p->nalloc*sizeof(finfo_t) );
00324                 if ( p->flist == NULL )
00325                 {
00326                     fprintf( stderr, "** FFV: failure to allocate %d finfo_t "
00327                                      "structs!\n", p->nalloc );
00328                     return -1;
00329                 }
00330 
00331                 if ( gD.level > 1 )
00332                     idisp_hf_param_t( "++ final realloc of flist : ", p );
00333             }
00334 
00335             /* use this volume to complete the geh.orients string */
00336             if ( complete_orients_str( v, p ) < 0 )
00337                 return -1;
00338 
00339             /* use this volume to note the byte order of image data */
00340             if ( check_im_byte_order( &ac->byte_order, v, p ) < 0 )
00341                 return -1;
00342 
00343             /* if wanted, verify afni link, send image info and first volume */
00344             if ( ac->state == ART_STATE_TO_OPEN )
00345                 ART_open_afni_link( ac, 5, 0, gD.level );
00346 
00347             if ( ac->state == ART_STATE_TO_SEND_CTRL )
00348                 ART_send_control_info( ac, v, gD.level );
00349 
00350             if ( ac->state == ART_STATE_IN_USE )
00351                     ART_send_volume( ac, v, gD.level );
00352 
00353             if ( gD.level > 1 )
00354             {
00355                 ART_idisp_ART_comm( "-- first vol ", ac );
00356                 idisp_im_store_t( "-- first vol ", &p->im_store );
00357             }
00358         }
00359         else
00360             return ret_val;             /* fatal error condition */
00361     }
00362 
00363     if ( ret_val > 0 )
00364         return 0;
00365     else
00366         return ret_val;
00367 }
00368 
00369 
00370 /*----------------------------------------------------------------------
00371  * find_more_volumes:   given first volume, keep scanning for others
00372  *
00373  * This function runs until a fatal error occurs.
00374  * 
00375  * return:     0 : on success
00376  *          else : error
00377  *----------------------------------------------------------------------
00378 */
00379 static int find_more_volumes( vol_t * v0, param_t * p, ART_comm * ac )
00380 {
00381     vol_t vn;
00382     int   ret_val, done;
00383     int   run, seq_num, next_im;
00384     int   fl_index;                     /* current index into p->flist    */
00385     int   naps;                         /* keep track of consecutive naps */
00386     int   nap_time;                     /* sleep time, in seconds         */
00387 
00388     if ( v0 == NULL || p == NULL )
00389     {
00390         fprintf( stderr, "error: IFM:FMV() lacking parameters\n" );
00391         return -1;
00392     }
00393 
00394     done     = 0;
00395     naps     = 0;
00396 
00397     run      = v0->run;
00398     seq_num  = v0->seq_num = 1;         /* set first seq_num to 1 */
00399     fl_index = v0->fn_n + 1;            /* start looking past first volume */
00400     next_im  = v0->fn_n + 1;            /* for read_ge_files()             */
00401 
00402     nap_time = nap_time_from_tr( v0->geh.tr );
00403 
00404     if ( gD.level > 0 )                 /* status */
00405     {
00406         fprintf( stderr, "-- scanning for additional volumes...\n" );
00407         fprintf( stderr, "-- run %d: %d ", run, seq_num );
00408     }
00409 
00410     /* give stats when user quits */
00411     signal( SIGTERM, hf_signal );
00412     signal( SIGINT,  hf_signal );
00413 
00414     if ( set_volume_stats( p, &gS, v0 ) )
00415         return -1;
00416 
00417     while ( ! done )
00418     {
00419         /* check all of the volumes we've already scanned in */
00420         ret_val = 1;
00421         while ( (ret_val == 1) || (ret_val == -1) )
00422         {
00423             ret_val = volume_match( v0, &vn, p, fl_index );
00424 
00425             if ( ret_val < -1 )                 /* bail out on fatal error */
00426                 return ret_val;
00427 
00428             if ( (ret_val == 1) || (ret_val == -1) )
00429             {
00430                 if ( gD.level > 2 )
00431                     idisp_hf_vol_t( "-- new volume: ", &vn );
00432 
00433                 fl_index += vn.nim;             /* note the new position   */
00434                 next_im   = vn.fn_n + 1;        /* for read_ge_files()     */
00435 
00436                 if ( vn.run != run )            /* new run?                */
00437                 {
00438                     /* pass run and seq_num before they are updated */
00439                     if ( ac->state == ART_STATE_IN_USE )
00440                         ART_send_end_of_run( ac, run, seq_num, gD.level );
00441 
00442                     run = vn.run;               /* reset                   */
00443                     seq_num = 1;
00444 
00445                     if ( gD.level > 0 )
00446                         fprintf( stderr, "\n-- run %d: %d ", run, seq_num );
00447                 }
00448                 else
00449                 {
00450                     seq_num++;
00451 
00452                     if ( gD.level > 0 )
00453                         fprintf( stderr, "%d ", seq_num );
00454                 }
00455 
00456                 vn.seq_num = seq_num;
00457 
00458                 if ( set_volume_stats( p, &gS, &vn ) )
00459                     return -1;
00460 
00461                 if ( complete_orients_str( &vn, p ) < 0 )
00462                     return -1;
00463 
00464                 if ( ac->state == ART_STATE_TO_SEND_CTRL )
00465                     ART_send_control_info( ac, &vn, gD.level );
00466 
00467                 /* only send good volumes to afni   - 2003.03.10 */
00468                 if ( (ac->state == ART_STATE_IN_USE) && (ret_val == 1) )
00469                     ART_send_volume( ac, &vn, gD.level );
00470 
00471                 naps = 0;                       /* reset on existing volume */
00472             }
00473         }
00474 
00475         /* now we need new data - skip past last file name index */
00476 
00477         ret_val = read_ge_files( p, next_im, p->nalloc );
00478         fl_index = 0;                   /* reset flist index          */
00479 
00480         while ( (ret_val >= 0 ) &&      /* no fatal error, and        */
00481                 (ret_val < v0->nim) )   /* didn't see full volume yet */
00482         {
00483             if ( naps > 0 )
00484             {
00485                 if ( p->opts.quit )     /* then we are outta here */
00486                 {
00487                     if ( ac->state == ART_STATE_IN_USE )
00488                         ART_send_end_of_run( ac, run, seq_num, gD.level );
00489 
00490                     show_run_stats( &gS );
00491                     return 0;
00492                 }
00493 
00494                 /* continue, regardless */
00495                 if ( check_stalled_run( run, seq_num, naps, nap_time ) > 0 )
00496                     if ( ac->state == ART_STATE_IN_USE )
00497                         ART_send_end_of_run( ac, run, seq_num, gD.level );
00498 
00499                 if ( gD.level > 0 )     /* status */
00500                     fprintf( stderr, ". " );
00501             }
00502 
00503             sleep( nap_time );          /* wake after a couple of TRs */
00504             naps ++;
00505 
00506             ret_val = read_ge_files( p, next_im, p->nalloc );
00507         }
00508 
00509         if ( ret_val < 0 )              /* aaaaagh!  panic!  wet pants! */
00510         {
00511             fprintf( stderr, "\n** failure: IFM:RGF fatal error\n" );
00512             return -1;
00513         }
00514     }
00515 
00516     return 0;   /* success */
00517 }
00518 
00519 
00520 /*----------------------------------------------------------------------
00521  * volume_search:   scan p->flist for a complete volume
00522  *
00523  *     - start should be at the expected beginning of a volume!
00524  *     - *fl_start may be returned as a new starting index into fnames
00525  * 
00526  * return:   -2 : on programming error
00527  *           -1 : on data error
00528  *            0 : on success - no volume yet
00529  *            1 : on success - volume read
00530  *----------------------------------------------------------------------
00531 */
00532 static int volume_search(
00533         vol_t   * V,                    /* volume to fill                 */
00534         param_t * p,                    /* master structure               */
00535         int       start,                /* starting index into p->flist   */
00536         int       maxsl,                /* max number of slices to check  */
00537         int     * fl_start )            /* return new fnames search point */
00538 {
00539     finfo_t * fp;
00540     float     z_orig, delta, dz, prev_z;
00541     int       bound;                    /* upper bound on image slice  */
00542     int       next;
00543     int       run0, run1;               /* run numbers, for comparison */
00544     int       first = start;            /* first image (start or s+1)  */
00545     int       last;                     /* final image in volume       */
00546 
00547     if ( V == NULL || p == NULL || p->flist == NULL || start < 0 )
00548     {
00549         fprintf( stderr, "failure: FNV: bad parameter data\n" );
00550         return -2;
00551     }
00552 
00553     /* note the bound on the slice index */
00554     if ( (maxsl <= 0) || ((maxsl + first) >= p->nused) )
00555         bound = p->nused;
00556     else
00557         bound = first + maxsl;
00558 
00559     if ( (bound - first) < 4 )          /* not enough data to work with   */
00560         return 0;
00561 
00562     delta = p->flist[first+1].geh.zoff - p->flist[first].geh.zoff;
00563 
00564     run0  = p->flist[first  ].geh.uv17;
00565     run1  = p->flist[first+1].geh.uv17;
00566 
00567     /* if apparent 1-slice volume, skip and start over */
00568     if ( (fabs(delta) < IFM_EPSILON) || (run1 != run0) )
00569     {
00570         if ( gD.level > 1 )
00571             fprintf( stderr, "-- skipping single slice volume <%s>\n",
00572                      p->fnames[p->flist[first].index] );
00573 
00574         first++;
00575         delta = p->flist[first+1].geh.zoff - p->flist[first].geh.zoff;
00576         run0  = run1;
00577 
00578         if ( fabs(delta) < IFM_EPSILON )
00579         {
00580             fprintf( stderr, "Error: 3 slices with 0 delta, beginning with"
00581                      "file <%s>\n", p->fnames[p->flist[start].index] );
00582 
00583             *fl_start = p->flist[start+2].index;
00584 
00585             return -1;
00586         }
00587     }
00588 
00589     fp     = p->flist + first;                  /* initialize flist posn  */
00590     z_orig = fp->geh.zoff;                      /* note original position */
00591 
00592     /* set current values at position (first+1) */
00593     fp++;
00594     prev_z = fp->geh.zoff;
00595     run1   = fp->geh.uv17;
00596     dz     = delta;
00597 
00598     /* scan for volume break */
00599     next = first + 2;                           /* next z to look at      */
00600     while ( (next < bound) && (fabs(dz - delta) < IFM_EPSILON) &&
00601             (run1 == run0) )
00602     {
00603         fp++;                             /* good index so get new values */
00604 
00605         dz     = fp->geh.zoff - prev_z;
00606         run1   = fp->geh.uv17;
00607         prev_z = fp->geh.zoff;
00608 
00609         next++;
00610     }
00611 
00612     last = next - 2;                        /* note final image in volume */
00613 
00614     if ( fabs(fp->geh.zoff - p->flist[first].geh.zoff) < IFM_EPSILON )
00615     {
00616         /* Current location is same as first, we have a volume! */
00617 
00618         /* So deltas are consistent from slice 'first' to slice 'last'. */
00619 
00620         V->geh      = p->flist[first].geh;         /* copy GE structure  */
00621         V->gex      = p->flist[first].gex;         /* copy GE extras     */
00622         V->nim      = last - first + 1;
00623         V->fl_1     = first;
00624         V->fn_1     = p->flist[first].index;
00625         V->fn_n     = p->flist[last].index;
00626         strncpy( V->first_file, p->fnames[V->fn_1], IFM_MAX_FLEN );
00627         strncpy( V->last_file,  p->fnames[V->fn_n], IFM_MAX_FLEN );
00628         V->z_first  = p->flist[first].geh.zoff;
00629         V->z_last   = p->flist[last].geh.zoff;
00630         V->z_delta  = delta;
00631         V->seq_num  = -1;                               /* uninitialized */
00632         V->run      = V->geh.uv17;
00633 
00634         return 1;
00635     }
00636     else if ( (fabs(dz - delta) < IFM_EPSILON) && (run1 == run0) )
00637         return 0;                           /* we did not finish a volume */
00638     else if ( dz * delta < 0.0 )
00639     {
00640         /* We have gone in the wrong direction.  This means that the
00641          * starting slice was not the first in the volume.  Try restarting
00642          * from the current position.
00643          */
00644         
00645         fprintf( stderr, "\n"
00646                 "*************************************************\n"
00647                 "Error: missing slice(s) in first volume!\n"
00648                 "       attempting to re-start at file: %s\n"
00649                 "*************************************************\n",
00650                 p->fnames[p->flist[last+1].index] );
00651 
00652         *fl_start = p->flist[last+1].index;
00653     }
00654     else    /* right direction, but bad delta */
00655     {
00656         /* the next slice does not match the original - interleaving? */
00657         int testc;
00658 
00659         for ( testc = next - 1; testc < bound; testc++ )
00660             if ( abs( p->flist[first].geh.zoff -
00661                       p->flist[testc].geh.zoff ) < IFM_EPSILON )
00662             {
00663                 /* aaaaagh!  we are missing data from the first volume!   */
00664                 /* print error, and try to skip this volume               */
00665                 fprintf( stderr, "\n"
00666                         "*************************************************\n"
00667                         "Error: missing slice in first volume!\n"
00668                         "       detected    at file: %s\n"
00669                         "       re-starting at file: %s\n"
00670                         "*************************************************\n",
00671                         p->fnames[p->flist[last+1].index],
00672                         p->fnames[p->flist[testc].index] );
00673 
00674                 /* try to skip this volume and recover */
00675                 *fl_start = p->flist[testc].index;
00676 
00677                 return -1;
00678             }
00679 
00680         /* we didn't find the original zoff, wait for more files */
00681         return 0;
00682     }
00683 
00684     return -1;  /* thank you, come again */
00685 }
00686 
00687 
00688 /*----------------------------------------------------------------------
00689  * volume_match:   scan p->flist for a matching volume
00690  *
00691  *     - start should be at the expected beginning of a volume!
00692  * 
00693  * return:   -2 : fatal error
00694  *           -1 : recoverable data error
00695  *            0 : on success - no volume yet
00696  *            1 : on success - volume read
00697  *----------------------------------------------------------------------
00698 */
00699 static int volume_match( vol_t * vin, vol_t * vout, param_t * p, int start )
00700 {
00701     static int   retry = 1;                             /* v2.12 */
00702     finfo_t    * fp;
00703     finfo_t    * fp_test;
00704     float        z;
00705     int          count, next_start = -1;
00706     int          missing = 0;
00707 
00708     if ( vin == NULL || vout == NULL ||
00709          p == NULL || p->flist == NULL || start < 0 )
00710     {
00711         fprintf( stderr, "failure: FMV: bad parameter data\n" );
00712         return -2;
00713     }
00714 
00715     if ( (p->nused - start) < vin->nim )        /* enough files to scan? */
00716         return 0;
00717 
00718     /* now 'everything' should match */
00719 
00720     fp = p->flist+start;
00721     for ( count = 0; count < vin->nim - 1; count++ )   /* last is separate */
00722     {
00723         z = vin->z_first + count * vin->z_delta;        /* note expected z */
00724 
00725         if ( fabs( z - fp->geh.zoff ) > IFM_EPSILON )
00726         {
00727             /* slice is either missing or out of order */
00728 
00729             fp_test = fp + 1;                          /* check next image */
00730             if ( fabs( z + vin->z_delta - fp_test->geh.zoff ) < IFM_EPSILON )
00731             {
00732                 /* report the error?                v2.12 */
00733                 if ( !check_error(&retry, vin->geh.tr, "slice out of order") )
00734                     return 0;
00735 
00736                 /* next slice as expected, so current is out of order */
00737                 /* nothing to do but warn the user and continue */
00738 
00739                 IFM_BIG_ERROR_MESG( "slice out of order!",
00740                         p->fnames[fp->index], z, fp->geh.zoff,
00741                         fp->geh.uv17, count + 1, vin->nim );
00742             }
00743             else if ( fabs(z + vin->z_delta - fp->geh.zoff) < IFM_EPSILON )
00744             {
00745                 /* current slice matches next expected - slice missing */
00746 
00747                 /* report the error? */
00748                 if ( !check_error(&retry, vin->geh.tr, "slice missing") )
00749                     return 0;
00750 
00751                 /* nothing to do but note error, warn user and continue */
00752                 missing++;
00753 
00754                 IFM_BIG_ERROR_MESG( "slice missing!",
00755                         p->fnames[fp->index], z, fp->geh.zoff,
00756                         fp->geh.uv17, count + 1, vin->nim );
00757 
00758                 count++;    /* attempt to continue by skipping this slice */
00759             }
00760             else        /* unknown error - find start of next volume */
00761             {
00762                 /* search for a next starting point */
00763                 next_start = find_next_zoff( p, start+count, vin->z_first );
00764 
00765                 if ( next_start < 0 )   /* come back and try again later */
00766                     return 0;
00767                 else
00768                 {
00769                     /* report error? */
00770                     if ( !check_error(&retry, vin->geh.tr, "vol toasted") )
00771                         return 0;
00772 
00773                     IFM_BIG_ERROR_MESG( "volume severely toasted!",
00774                             p->fnames[fp->index], z, fp->geh.zoff,
00775                             fp->geh.uv17, count + 1, vin->nim );
00776 
00777                     break;      /* terminate for loop and try to recover */
00778                 }
00779             }
00780         }
00781 
00782         fp++;
00783     }
00784 
00785     z = vin->z_first + count * vin->z_delta;      /* note expected z   */
00786 
00787     if ( count >= vin->nim )    /* missed second to last slice */
00788         next_start = start + vin->nim - missing;
00789     else if ( (next_start < 0) && (fabs( z - fp->geh.zoff ) > IFM_EPSILON) )
00790     {
00791         /* check last slice - count and fp should be okay*/
00792         if ( (p->nused - start) <= vin->nim )   /* no more images to check */
00793             return 0;                           /* wait for more data      */
00794         
00795         fp_test = fp + 1;                              /* check next image */
00796         if ( fabs( vin->z_first - fp_test->geh.zoff ) < IFM_EPSILON )
00797         {
00798             /* next image starts next run, slice is probably out of order */
00799 
00800             /* report error? */
00801             if ( !check_error(&retry, vin->geh.tr, "last slice out of order") )
00802                 return 0;
00803 
00804             IFM_BIG_ERROR_MESG( "last slice out of order!",
00805                     p->fnames[fp->index], z, fp->geh.zoff,
00806                     fp->geh.uv17, count + 1, vin->nim );
00807         }
00808         else if ( fabs(vin->z_first - fp->geh.zoff) < IFM_EPSILON )
00809         {
00810             /* this image starts next run, slice is missing */
00811 
00812             /* report error? */
00813             if ( !check_error(&retry, vin->geh.tr, "last slice missing") )
00814                 return 0;
00815 
00816             missing++;
00817 
00818             IFM_BIG_ERROR_MESG( "last slice missing!",
00819                     p->fnames[fp->index], z, fp->geh.zoff,
00820                     fp->geh.uv17, count + 1, vin->nim );
00821         }
00822         else    /* unknown error - find start of next volume */
00823         {
00824             /* search for a next starting point */
00825             next_start = find_next_zoff( p, start+count+1, vin->z_first );
00826 
00827             if ( next_start < 0 )       /* come back and try again later */
00828                 return 0;
00829             else
00830             {
00831                 /* report error? */
00832                 if ( !check_error(&retry, vin->geh.tr, "Vol toasted") )
00833                     return 0;
00834 
00835                 IFM_BIG_ERROR_MESG( "Volume severely toasted!",
00836                         p->fnames[fp->index], z, fp->geh.zoff,
00837                         fp->geh.uv17, count + 1, vin->nim );
00838             }
00839         }
00840     }
00841 
00842     if ( next_start < 0)
00843         next_start = start + vin->nim - missing;
00844 
00845     if ( retry == 0 && gD.level > 0 )                   /* v2.12 */
00846         fprintf(stderr," (retry OK - no errors)\n");
00847 
00848     retry = 1;                          /* next error gets two tries - v2.12 */
00849 
00850     /* fill volume structure */
00851 
00852     vout->geh      = p->flist[start].geh;
00853     vout->gex      = p->flist[start].gex;
00854     vout->nim      = next_start - start;
00855     vout->fl_1     = start;
00856     vout->fn_1     = p->flist[start].index;
00857     vout->fn_n     = p->flist[start+vout->nim-1].index;
00858     strncpy( vout->first_file, p->fnames[vout->fn_1], IFM_MAX_FLEN );
00859     strncpy( vout->last_file,  p->fnames[vout->fn_n],  IFM_MAX_FLEN );
00860     vout->z_first  = vin->z_first;
00861     vout->z_last   = vin->z_last;
00862     vout->z_delta  = vin->z_delta;
00863     vout->seq_num  = -1;                                /* uninitialized */
00864     vout->run      = vout->geh.uv17;
00865 
00866     if ( vout->nim != vin->nim )
00867         return -1;
00868     else
00869         return 1;
00870 }
00871 
00872 /*----------------------------------------------------------------------
00873  * check_error:         only report error on second failure     v2.12
00874  *
00875  * return:  < 0  : on programming error
00876  *            0  : do not report error yet
00877  *            1  : report error
00878  *----------------------------------------------------------------------
00879 */
00880 static int check_error( int * retry, float tr, char * note )
00881 {
00882     if ( !retry )
00883         return -1;
00884 
00885     if ( *retry == 1 )
00886     {
00887         /* let user know we're checking */
00888         if ( gD.level > 0 )
00889             fprintf(stderr," (volume retry test for warning '%s'...)\n",
00890                     CHECK_NULL_STR(note));
00891 
00892         *retry = 0;
00893         sleep( nap_time_from_tr(tr) );
00894         return 0;
00895     }
00896 
00897     /* so calling function should print error */
00898 
00899     *retry = 2;
00900 
00901     return 1;
00902 }
00903 
00904 
00905 /*----------------------------------------------------------------------
00906  * read_ge_files:
00907  *
00908  *     - sanity checks
00909  *     - read_directory (free any old file expansion list)
00910  *     - decide number of files to scan (max == 0 implies the rest)
00911  *     - allocate necessary p->flist memory
00912  *     - read GE structures
00913  * 
00914  * return:       < 0  : on error
00915  *         files read : on success
00916  *----------------------------------------------------------------------
00917 */
00918 static int read_ge_files(
00919         param_t * p,            /* parameter scruct                */
00920         int       start,        /* index of next file to scan from */
00921         int       max )         /* max number of files to scan     */
00922 {
00923     int n2scan;                 /* number of files to actually scan */
00924     int next = start;           /* initialize next index to start   */
00925 
00926     if ( p == NULL )
00927     {
00928         fputs( "failure: RAF: no param_t struct\n", stderr  );
00929         return -1;
00930     }
00931 
00932     /* clear away old file list */
00933     if ( p->fnames != NULL )
00934     {
00935         if ( p->nfiles <= 0 )
00936         {
00937             fputs( "failure: RAF: fnames does not match nfiles\n", stderr );
00938             return -1;
00939         }
00940 
00941         MCW_free_expand( p->nfiles, p->fnames );
00942         p->fnames = NULL;
00943     }
00944 
00945     /* get files */
00946     MCW_file_expand( 1, &p->glob_dir, &p->nfiles, &p->fnames );
00947 
00948     /* if next is 0, search for any first_file */
00949     if ( (next == 0 ) && (p->opts.start_file != NULL) )
00950     {
00951         next = find_fl_file_index( p, p->opts.start_file );
00952 
00953         if ( next < 0 )         /* if not found, try again later */
00954         {
00955             if ( gD.level > 0 ) /* inform the user */
00956             {
00957                 static int attempts = 0;
00958 
00959                 if ( attempts == 0 )
00960                     fprintf(stderr, "-- still searching for start_file, '%s'\n",
00961                             p->opts.start_file );
00962 
00963                 attempts++;
00964             }
00965             return 0;
00966         }
00967     }
00968     
00969     if ( gD.level > 3 )
00970     {
00971         int fnum;
00972         for ( fnum = next; fnum < p->nfiles; fnum++ )
00973             printf( "file %4d: %s\n", fnum, p->fnames[fnum] );
00974     }
00975 
00976     if ( p->nfiles <= 0 )
00977         return 0;
00978 
00979     /* set the number of files to scan - if max is usable, use it */
00980     if ( (max > 0) && (max <= (p->nfiles - next)) )
00981         n2scan = max;                           /* scan next max files */
00982     else
00983         n2scan = p->nfiles - next;              /* scan rest of files  */
00984 
00985     /* do we need/want more memory? */
00986     if ( (n2scan > p->nalloc) || (max > p->nalloc) )
00987     {
00988         int nalloc;
00989 
00990         /* allow a request to allocate 'max' entries */
00991         nalloc = (n2scan >= max) ? n2scan : max;
00992 
00993         p->flist = (finfo_t *)realloc( p->flist, nalloc * sizeof(finfo_t) );
00994 
00995         if ( p->flist == NULL )
00996         {
00997             fprintf(stderr, "failure to allocate %d finfo_t structs\n", nalloc);
00998             return -1;
00999         }
01000 
01001         p->nalloc = nalloc;
01002 
01003         if ( gD.level > 1 )
01004         {
01005             idisp_hf_param_t( "++ realloc of flist : ", p );
01006             fprintf( stderr,  "-- n2scan = %d, max = %d\n", n2scan, max );
01007         }
01008     }
01009 
01010     p->nused = scan_ge_files( p, next, n2scan );
01011 
01012     if ( gD.level > 2 )
01013         idisp_hf_param_t( "end read_ge_files : ", p );
01014 
01015     /* may be negative for an error condition */
01016     return p->nused;
01017 }
01018 
01019 /*----------------------------------------------------------------------
01020  * scan_ge_files:
01021  *
01022  * Starting at index 'next' of 'fnames', scan 'nfiles' files,
01023  * filling the 'flist' array.
01024  *----------------------------------------------------------------------
01025 */
01026 static int scan_ge_files (
01027         param_t  * p,                   /* general parameter structure */
01028         int        next,                /* index of next file to scan  */
01029         int        nfiles )             /* number of files to scan     */
01030 {
01031     finfo_t    * fp;
01032     int          im_num, fnum;
01033     int          files_read, rv;
01034     int          need_M;                /* do we need image memory?    */
01035 
01036     if ( nfiles <= 0 )
01037         return 0;
01038 
01039     if ( check_im_store_space( &p->im_store, nfiles ) < 0 )
01040         return -1;
01041 
01042     p->im_store.nused = 0;
01043     /* scan from 'next' to 'next + nfiles - 1' */
01044     for ( im_num = 0, fnum = next, fp = p->flist;
01045           im_num < nfiles;
01046           im_num++, fnum++, fp++ )
01047     {
01048         if ( im_num < p->im_store.nalloc )      /* then we have image memory */
01049         {
01050             fp->image = p->im_store.im_ary[im_num];
01051             need_M    = 0;
01052         }
01053         else                                    /* get it from read_ge_image */
01054         {
01055             fp->image = NULL;
01056             need_M    = 1;
01057         }
01058 
01059         rv = read_ge_image( p->fnames[fnum], fp, 1, need_M );
01060 
01061         /* don't lose any allocated memory, regardless of the return value */
01062         if ( (need_M == 1) && (fp->image != NULL) )
01063         {
01064             p->im_store.im_ary[im_num] = fp->image;
01065             p->im_store.nalloc++;
01066 
01067             /* note the size of the image and get memory for x_im */
01068             if ( p->im_store.im_size == 0 )
01069             {
01070                 if ( alloc_x_im( &p->im_store, fp->bytes ) < 0 )
01071                     return -1;
01072             }
01073 
01074             if ( gD.level > 1 )
01075                 fprintf( stderr, "++ allocated image %d at address %p\n",
01076                          im_num, p->im_store.im_ary[im_num] );
01077         }
01078 
01079         if ( (rv != 0) || (fp->geh.good != 1) )
01080         {
01081             static int read_failure = -1;  /* last read_ge_image failure    */
01082             static int fail_count   =  0;  /* get multiple tries to succeed */
01083 
01084             /* on first failure, note file and set fail_count to 1 */
01085             if ( read_failure != fnum )
01086             {
01087                 read_failure = fnum;
01088                 fail_count   = 1;
01089             }
01090             else
01091                 fail_count++;
01092 
01093             /* after too many failure, we give up */
01094             if ( fail_count > IFM_MAX_GE_FAILURES )
01095             {
01096                 fprintf( stderr, "\n** failure: cannot read GE header for "
01097                          "file <%s>\n", p->fnames[fnum] );
01098                 return -1;
01099             }
01100 
01101             /* we failed, but will try again later - maybe inform user */
01102             if ( gD.level > 1 )
01103                 fprintf( stderr, "\n-- (%d) failures to read GE header for "
01104                          "file <%s>, trying again...\n",
01105                          fail_count, p->fnames[fnum] );
01106 
01107             break;
01108         }
01109         else
01110         {
01111             p->im_store.nused++;        /* keep track of used images     */
01112             fp->index = fnum;           /* store index into fnames array */
01113 
01114             if ( gD.level > 2 )
01115             {
01116                 idisp_ge_header_info( p->fnames[fp->index], &fp->geh );
01117                 idisp_ge_extras( p->fnames[fp->index], &fp->gex );
01118             }
01119         }
01120     }
01121 
01122     /* even on failure, this non-negative integer is accurate */
01123     files_read = fnum - next;
01124 
01125     if ( gD.level > 1 )
01126         printf( "-- scanned %d GE files, from <%s> to <%s>\n",
01127                 files_read, p->fnames[next], p->fnames[next+files_read-1] );
01128 
01129     return files_read;
01130 }
01131 
01132 
01133 /*----------------------------------------------------------------------
01134  * init_options:
01135  *
01136  *     1. check usage: Imon -start_dir DIR
01137  *     2. do initial allocation of data structures
01138  *----------------------------------------------------------------------
01139 */
01140 static int init_options( param_t * p, ART_comm * A, int argc, char * argv[] )
01141 {
01142     int ac, errors = 0;
01143 
01144     if ( p == NULL )
01145         return 2;
01146 
01147     if ( argc < 2 )
01148     {
01149         usage( IFM_PROG_NAME, IFM_USE_SHORT );
01150         return 1;
01151     }
01152 
01153     /* basic initialization of data structures */
01154 
01155     memset(  p,  0, sizeof(*p)  );      /* parameters       */
01156     memset( &gD, 0, sizeof(gD)  );      /* debug struct     */
01157     memset( &gS, 0, sizeof(gS)  );      /* stats struct     */
01158     memset(  A,  0, sizeof(gAC) );      /* afni comm struct */
01159 
01160     ART_init_AC_struct( A );            /* init for no real-time comm */
01161     A->param = p;                       /* store the param_t pointer  */
01162 
01163     empty_string_list( &p->opts.drive_list, 0 );
01164     empty_string_list( &p->opts.rt_list, 0 );
01165 
01166     /* debug level 1 is now the default - by order of Wen-Ming :) */
01167     gD.level = 1;
01168 
01169     for ( ac = 1; ac < argc; ac++ )
01170     {
01171         if ( ! strncmp( argv[ac], "-debug", 4 ) )
01172         {
01173             if ( ++ac >= argc )
01174             {
01175                 fputs( "option usage: -debug LEVEL\n", stderr );
01176                 usage( IFM_PROG_NAME, IFM_USE_SHORT );
01177                 return 1;
01178             }
01179 
01180             p->opts.debug = atoi(argv[ac]);
01181             gD.level      = p->opts.debug;
01182             if ( gD.level < 0 || gD.level > IFM_MAX_DEBUG )
01183             {
01184                 fprintf( stderr, "error: debug level must be in [0,%d]\n",
01185                          IFM_MAX_DEBUG );
01186                 errors++;
01187             }
01188         }
01189         else if ( ! strncmp( argv[ac], "-GERT_Reco2", 7 ) )
01190         {
01191             p->opts.gert_reco = 1;      /* output script at the end */
01192         }
01193         else if ( ! strncmp( argv[ac], "-help", 5 ) )
01194         {
01195             usage( IFM_PROG_NAME, IFM_USE_LONG );
01196             return 1;
01197         }
01198         else if ( ! strncmp( argv[ac], "-hist", 5 ) )
01199         {
01200             usage( IFM_PROG_NAME, IFM_USE_HIST );
01201             return 1;
01202         }
01203         else if ( ! strncmp( argv[ac], "-nice", 4 ) )
01204         {
01205             if ( ++ac >= argc )
01206             {
01207                 fputs( "option usage: -nice INCREMENT\n", stderr );
01208                 usage( IFM_PROG_NAME, IFM_USE_SHORT );
01209                 return 1;
01210             }
01211 
01212             p->opts.nice = atoi(argv[ac]);
01213             if ( (p->opts.nice < IFM_MIN_NICE_INC) ||
01214                  (p->opts.nice > IFM_MAX_NICE_INC) )
01215             {
01216                 fprintf( stderr, "error: nice incrment must be in [%d,%d]\n",
01217                          IFM_MIN_NICE_INC, IFM_MAX_NICE_INC );
01218                 errors++;
01219             }
01220         }
01221         else if ( ! strncmp( argv[ac], "-nt", 3 ) )
01222         {
01223             if ( ++ac >= argc )
01224             {
01225                 fputs( "option usage: -nt VOLUMES_PER_RUN\n", stderr );
01226                 usage( IFM_PROG_NAME, IFM_USE_SHORT );
01227                 return 1;
01228             }
01229 
01230             p->opts.nt = atoi(argv[ac]);
01231             if ( p->opts.nt < 0 || p->opts.nt > IFM_MAX_NT )
01232             {
01233                 fprintf( stderr,
01234                     "option usage: -nt VOLUMES_PER_RUN\n"
01235                     "       error: VOLUMES_PER_RUN must be in [%d,%d]\n",
01236                     0, IFM_MAX_NT );
01237                 errors++;
01238             }
01239         }
01240         else if ( ! strncmp( argv[ac], "-od", 3 ) ||
01241                   ! strncmp( argv[ac], "-gert_outdir", 9 ) )
01242         {
01243             if ( ++ac >= argc )
01244             {
01245                 fputs( "option usage: -gert_outdir OUTPUT_DIR\n", stderr );
01246                 usage( IFM_PROG_NAME, IFM_USE_SHORT );
01247                 return 1;
01248             }
01249 
01250             p->opts.gert_outdir = argv[ac];
01251         }
01252         else if ( ! strncmp( argv[ac], "-quiet", 6 ) )
01253         {
01254             /* only go quiet if '-debug' option has not changed it */
01255             if ( gD.level == IFM_DEBUG_DEFAULT )
01256                 gD.level = 0;
01257         }
01258         else if ( ! strncmp( argv[ac], "-quit", 5 ) )
01259         {
01260             p->opts.quit = 1;
01261         }
01262         else if ( ! strncmp( argv[ac], "-sp", 3 ) )
01263         {
01264             if ( ++ac >= argc )
01265             {
01266                 fputs( "option usage: -sp PATTERN\n", stderr );
01267                 usage( IFM_PROG_NAME, IFM_USE_SHORT );
01268                 return 1;
01269             }
01270 
01271             p->opts.sp = argv[ac];
01272         }
01273         else if ( ! strncmp( argv[ac], "-start_dir", 8 ) )
01274         {
01275             if ( ++ac >= argc )
01276             {
01277                 fputs( "option usage: -start_dir DIRECTORY\n", stderr );
01278                 usage( IFM_PROG_NAME, IFM_USE_SHORT );
01279                 return 1;
01280             }
01281 
01282             p->opts.start_dir = argv[ac];
01283         }
01284         else if ( ! strncmp( argv[ac], "-start_file", 8 ) )
01285         {
01286             if ( ++ac >= argc )
01287             {
01288                 fputs( "option usage: -start_file DIR/FIRST_FILE\n", stderr );
01289                 usage( IFM_PROG_NAME, IFM_USE_SHORT );
01290                 return 1;
01291             }
01292 
01293             p->opts.start_file = argv[ac];
01294         }
01295         else if ( ! strncmp( argv[ac], "-version", 2 ) )
01296         {
01297             usage( IFM_PROG_NAME, IFM_USE_VERSION );
01298             return 1;
01299         }
01300         /* real-time options */
01301         else if ( ! strncmp( argv[ac], "-drive_afni", 6 ) )
01302         {
01303             if ( ++ac >= argc )
01304             {
01305                 fputs( "option usage: -drive_afni COMMAND\n", stderr );
01306                 usage( IFM_PROG_NAME, IFM_USE_SHORT );
01307                 return 1;
01308             }
01309 
01310             if ( add_to_string_list( &p->opts.drive_list, argv[ac] ) != 0 )
01311             {
01312                 fprintf(stderr,"** failed add '%s' to drive_list\n",argv[ac]);
01313                 return 1;
01314             }
01315         }
01316         else if ( ! strncmp( argv[ac], "-host", 4 ) )
01317         {
01318             if ( ++ac >= argc )
01319             {
01320                 fputs( "option usage: -host HOSTNAME\n", stderr );
01321                 usage( IFM_PROG_NAME, IFM_USE_SHORT );
01322                 return 1;
01323             }
01324 
01325             p->opts.host = argv[ac];    /* note and store the user option   */
01326             strncpy( A->host, argv[ac], ART_NAME_LEN-1 );
01327             A->host[ART_NAME_LEN-1] = '\0';     /* just to be sure */
01328         }
01329         else if ( ! strncmp( argv[ac], "-rev_byte_order", 4 ) )
01330         {
01331             p->opts.rev_bo = 1;           /* note to send reverse byte order */
01332         }
01333         else if ( ! strncmp( argv[ac], "-rt_cmd", 6 ) )
01334         {
01335             if ( ++ac >= argc )
01336             {
01337                 fputs( "option usage: -rt_cmd COMMAND\n", stderr );
01338                 usage( IFM_PROG_NAME, IFM_USE_SHORT );
01339                 return 1;
01340             }
01341 
01342             if ( add_to_string_list( &p->opts.rt_list, argv[ac] ) != 0 )
01343             {
01344                 fprintf(stderr,"** failed add '%s' to rt_list\n",argv[ac]);
01345                 return 1;
01346             }
01347         }
01348         else if ( ! strncmp( argv[ac], "-rt", 3 ) )
01349         {
01350             A->state = ART_STATE_TO_OPEN; /* real-time is open for business */
01351             p->opts.rt = 1;               /* just note the user option      */
01352         }
01353         else if ( ! strncmp( argv[ac], "-swap", 5 ) )
01354         {
01355             A->swap = 1;                /* do byte swapping before sending  */
01356             p->opts.swap = 1;           /* just note the user option        */
01357         }
01358         else if ( ! strncmp( argv[ac], "-zorder", 6 ) )
01359         {
01360             if ( ++ac >= argc )
01361             {
01362                 fputs( "option usage: -zorder ORDER\n", stderr );
01363                 usage( IFM_PROG_NAME, IFM_USE_SHORT );
01364                 return 1;
01365             }
01366 
01367             A->zorder = argv[ac];
01368         }
01369         else
01370         {
01371             fprintf( stderr, "error: invalid option <%s>\n\n", argv[ac] );
01372             usage( IFM_PROG_NAME, IFM_USE_SHORT );
01373             return 1;
01374         }
01375     }
01376 
01377     if ( errors > 0 )          /* check for all minor errors before exiting */
01378     {
01379         usage( IFM_PROG_NAME, IFM_USE_SHORT );
01380         return 1;
01381     }
01382 
01383     if ( p->opts.start_dir == NULL )
01384     {
01385         fputs( "error: missing '-start_dir DIR' option\n", stderr );
01386         usage( IFM_PROG_NAME, IFM_USE_SHORT );
01387         return 1;
01388     }
01389 
01390     if ( p->opts.rev_bo && p->opts.swap )
01391     {
01392         fprintf( stderr, "error: options '-rev_byte_order' and '-swap' "
01393                  "cannot both be used\n");
01394         usage( IFM_PROG_NAME, IFM_USE_SHORT );
01395         return 1;
01396     }
01397 
01398     if ( A->zorder )
01399     {
01400         if ( strcmp(A->zorder, "alt") && strcmp(A->zorder, "seq") )
01401         {
01402             fprintf(stderr,"** order '%s' is invalid for '-zorder' option,\n"
01403                     "   must be either 'alt' or 'seq'\n", A->zorder);
01404             return -1;
01405         }
01406     }
01407 
01408     /* done processing argument list */
01409 
01410     if ( dir_expansion_form( p->opts.start_dir, &p->glob_dir ) != 0 )
01411         return 2;
01412 
01413     /* save command arguments to add as a NOTE to any AFNI datasets */
01414     p->opts.argv = argv;
01415     p->opts.argc = argc;
01416 
01417     p->ftype     = IFM_IM_FTYPE_GEMS5;   /* 27 May 2005 */
01418 
01419     if ( gD.level > 1 )
01420     {
01421         idisp_hf_opts_t ( "end init_options : ", &p->opts );
01422         idisp_hf_param_t( "end init_options : ", p );
01423     }
01424 
01425     if ( gD.level > 0 )
01426         fprintf( stderr, "\n%s running, use <ctrl-c> to quit...\n\n",
01427                  IFM_PROG_NAME );
01428 
01429     return 0;
01430 }
01431 
01432 
01433 /*----------------------------------------------------------------------
01434  * initialize:
01435  *     - nice level
01436  *     - afni communications
01437  *     - verify that any passed 'start_file' "matches" 'start_dir'
01438  *       (for now, just do this by comparing directory depth)
01439  *----------------------------------------------------------------------
01440 */
01441 static int init_extras( param_t * p, ART_comm * ac )
01442 {
01443     if ( p->opts.nice && set_nice_level(p->opts.nice) )
01444         return 1;
01445 
01446     if ( ac->state == ART_STATE_TO_OPEN )            /* open afni comm link */
01447     {
01448         atexit( ART_exit );
01449         ac->mode = AFNI_OPEN_CONTROL_MODE;
01450         ART_open_afni_link( ac, 2, 1, gD.level );
01451     }
01452     
01453     /* check directory depth of start_file against glob_dir */
01454     if ( p->opts.start_file != NULL )
01455     {
01456         char * sf     = p->opts.start_file;
01457         char * gd     = p->glob_dir;
01458         int    flevel = str_char_count( sf, strlen(sf), (char)'/' );
01459 
01460         /* check whether the number of slashes match */
01461         if ( flevel != str_char_count( gd, strlen(gd), (char)'/' ) )
01462         {
01463             fprintf( stderr,
01464                      "** warning : relative path to       : '-start_dir  %s'\n"
01465                      "             does not seem to match : '-start_file %s'\n"
01466                      "             (so 'start_file' may never be found)\n\n",
01467                      p->opts.start_file, p->opts.start_dir );
01468         }
01469         else if ( gD.level > 1 )
01470             fprintf( stderr, "-- '-start_file %s' and\n"
01471                              "   '-start_dir  %s' match at dir level %d\n",
01472                              p->opts.start_file, p->opts.start_dir, flevel );
01473     }
01474 
01475     return 0;
01476 }
01477 
01478 
01479 /*----------------------------------------------------------------------
01480  *  set_nice_level              - set to given "nice" value
01481  *
01482  *  returns:   0  : success
01483  *           else : failure
01484  *----------------------------------------------------------------------
01485 */
01486 static int set_nice_level( int level )
01487 {
01488     int rv;
01489 
01490     rv = nice( level );
01491     if ( rv != 0 )
01492     {
01493         if ( level < 0 )
01494             fprintf( stderr, "error: only root may decrement nice value\n"
01495                              "       (errno = %d, rv = %d)\n", errno, rv );
01496         else
01497             fprintf( stderr,
01498                      "error: failure to adjust nice by %d\n"
01499                      "       (errno = %d, rv = %d)\n", level, errno, rv );
01500     }
01501     else if ( gD.level > 1 )
01502         fprintf( stderr, "-- nice value incremented by %d\n", level );
01503 
01504     return rv;
01505 }
01506 
01507 
01508 /*------------------------------------------------------------
01509  *  dir_expansion_form
01510  *
01511  *  sin    : must be in the form "...0[01]n", where n is a digit
01512  *           (note that "...0[01]n/..." is okay)
01513  *  sexp   : memory is allocated for the output string of the
01514  *           form: "...[0-9][02468]n/I.*"
01515  *
01516  *  returns:    0 : on success
01517  *           else : error
01518  *------------------------------------------------------------
01519 */
01520 int dir_expansion_form( char * sin, char ** sexp )
01521 {
01522     char * out;
01523     char * cp;
01524     char   d0, d1, d2;                  /* the three relevant digits */
01525     int    len;
01526 
01527     if ( (sin == NULL) || (sexp == NULL) )
01528         return -1;
01529 
01530     *sexp = NULL;
01531     len = strlen(sin);
01532 
01533     out = (char *)malloc((len + IFM_PAD_LEN) * sizeof(char));
01534     if ( out == NULL )
01535     {
01536         fprintf( stderr, "failure: dir_expansion_form malloc\n" );
01537         return -1;
01538     }
01539 
01540     *sexp = out;                        /* save resulting malloc'd address */
01541 
01542     strcpy( out,sin );
01543 
01544     cp = out + len - 1;                         /* point to end */
01545 
01546     /* we'd better find 0[01]n - ignore the rest??? */
01547     while ( (cp > (out+2)) && !isdigit( *cp ) )
01548         cp--;
01549 
01550     if ( !isdigit(*cp) )                        /* didn't find even one */
01551     {
01552         fprintf( stderr, "error: dir <%s> is not of the form 00n (e.g. 003)\n",
01553                  sin );
01554         free(out);
01555         return -1;
01556     }
01557 
01558     cp -= 2;                                    /* should be first zero  */
01559 
01560     d0 = cp[0];                                 /* note the three digits */
01561     d1 = cp[1];
01562     d2 = cp[2];
01563 
01564     if ( (d0 != '0') ||                         /* first is not a zero   */
01565          ( (d1 != '0') && (d1 != '1')) )        /* second is not 0 or 1  */
01566     {
01567         fprintf( stderr, "error: dir <%s> is not of the form 0[01]n"
01568                          " (e.g. 003)\n", sin );
01569         free(out);
01570         return -1;
01571     }
01572 
01573     /* woohooo!  we're good to go! */
01574     /* set to "...[0-9][02468]n/I.*" (or with [13579]) */
01575 
01576     strcpy( cp, "[0-9]" );                      /* add and skip "[0-9]" */
01577     cp += strlen( "[0-9]" );
01578 
01579     if ( d1 == '0' )                            /* adding 2 to each     */
01580         strcpy( cp, "[02468]" );
01581     else
01582         strcpy( cp, "[13579]" );
01583     cp += strlen( "[02468]" );
01584 
01585     *cp++ = d2;                                 /* insert final digit */
01586 
01587     /* allow either I.* or i.*  - v2.11 */
01588     strcpy( cp, "/[Ii].*" );                    /* the big finish */
01589 
01590     return 0;
01591 }
01592 
01593 
01594 /*----------------------------------------------------------------------
01595  *  read_ge_image  (basically from Ifile.c, but use file_tool.c version)
01596  *
01597  *  returns:   0  : success
01598  *           < 0  : failure
01599  *----------------------------------------------------------------------
01600 */
01601 static int read_ge_image( char * pathname, finfo_t * fp,
01602                           int get_image, int need_memory )
01603 {
01604    ge_header_info * hi  = &fp->geh;
01605 
01606    FILE *imfile ;
01607    int  length , skip , swap=0 ;
01608    char orients[8] , str[8] ;
01609    int nx , ny , bpp , cflag , hdroff ;
01610         float uv17 = -1.0;
01611         
01612    if( hi == NULL ) return -1;            /* bad */
01613    hi->good = 0 ;                       /* not good yet */
01614    if( pathname    == NULL ||
01615        pathname[0] == '\0'   ) return -1; /* bad */
01616 
01617    length = l_THD_filesize( pathname ) ;
01618    if( length < 1024 ) return -1;         /* bad */
01619 
01620    imfile = fopen( pathname , "r" ) ;
01621    if( imfile == NULL ) return -1;        /* bad */
01622 
01623    strcpy(str,"JUNK") ;     /* initialize string */
01624    fread(str,1,4,imfile) ;  /* check for "IMGF" at start of file */
01625 
01626    if( str[0]!='I' || str[1]!='M' || str[2]!='G' || str[3]!='F' ){ /* bad */
01627       fclose(imfile) ; return -2;
01628    }
01629 
01630    /*-- read next 5 ints (after the "IMGF" string) --*/
01631 
01632    fread( &skip , 4,1, imfile ) ; /* offset into file of image data */
01633    fread( &nx   , 4,1, imfile ) ; /* x-size */
01634    fread( &ny   , 4,1, imfile ) ; /* y-size */
01635    fread( &bpp  , 4,1, imfile ) ; /* bits per pixel (should be 16) */
01636    fread( &cflag, 4,1, imfile ) ; /* compression flag (1=uncompressed)*/
01637 
01638         /*-- check if nx is funny --*/
01639 
01640    if( nx < 0 || nx > 8192 ){      /* have to byte swap these 5 ints */
01641      swap = 1 ;                    /* flag to swap data, too */
01642      swap_4(&skip); swap_4(&nx); swap_4(&ny); swap_4(&bpp); swap_4(&cflag);
01643    } else {
01644      swap = 0 ;  /* data is ordered for this CPU */
01645    }
01646    if( nx < 0 || nx > 8192 || ny < 0 || ny > 8192 ){  /* bad */
01647       fclose(imfile) ; return -1;
01648    }
01649 
01650    hi->nx = nx ;
01651    hi->ny = ny ;
01652 
01653    if( skip+2*nx*ny >  length ||               /* file is too short */
01654        skip         <= 0      ||               /* bizarre  */
01655        cflag        != 1      ||               /* data is compressed */
01656        bpp          != 16        ){
01657       fclose(imfile); return -1;    /* data is not shorts */
01658    }
01659 
01660    /*-- try to read image header data as well --*/
01661 
01662    fseek( imfile , 148L , SEEK_SET ) ; /* magic GEMS offset */
01663    fread( &hdroff , 4,1 , imfile ) ;   /* location of image header */
01664    if( swap ) swap_4(&hdroff) ;
01665 
01666    if( hdroff > 0 && hdroff+256 < length ){   /* can read from image header */
01667        float dx,dy,dz, xyz[9], zz ; int itr, ii,jj,kk ;
01668 
01669        /*-- get voxel grid sizes --*/
01670 
01671        fseek( imfile , hdroff+26 , SEEK_SET ) ;    /* dz */
01672        fread( &dz , 4,1 , imfile ) ;
01673 
01674        fseek( imfile , hdroff+50 , SEEK_SET ) ;    /* dx and dy */
01675        fread( &dx , 4,1 , imfile ) ;
01676        fread( &dy , 4,1 , imfile ) ;
01677 
01678        if( swap ){ swap_4(&dx); swap_4(&dy); swap_4(&dz); }
01679 
01680        hi->dx = dx ; hi->dy = dy ; hi->dz = dz ;
01681 
01682        /* grid orientation: from 3 sets of LPI corner coordinates: */
01683        /*   xyz[0..2] = top left hand corner of image     (TLHC)   */
01684        /*   xyz[3..5] = top right hand corner of image    (TRHC)   */
01685        /*   xyz[6..8] = bottom right hand corner of image (BRHC)   */
01686        /* GEMS coordinate orientation here is LPI                  */
01687 
01688        fseek( imfile , hdroff+154 , SEEK_SET ) ;  /* another magic number */
01689        fread( xyz , 4,9 , imfile ) ;
01690        if( swap ){
01691           swap_4(xyz+0); swap_4(xyz+1); swap_4(xyz+2);
01692           swap_4(xyz+3); swap_4(xyz+4); swap_4(xyz+5);
01693           swap_4(xyz+6); swap_4(xyz+7); swap_4(xyz+8);
01694        }
01695 
01696        /* x-axis orientation */
01697        /* ii determines which spatial direction is x-axis  */
01698        /* and is the direction that has the biggest change */
01699        /* between the TLHC and TRHC                        */
01700 
01701        dx = fabs(xyz[3]-xyz[0]) ; ii = 1 ;
01702        dy = fabs(xyz[4]-xyz[1]) ; if( dy > dx ){ ii=2; dx=dy; }
01703        dz = fabs(xyz[5]-xyz[2]) ; if( dz > dx ){ ii=3;        }
01704        dx = xyz[ii+2]-xyz[ii-1] ; if( dx < 0. ){ ii = -ii;    }
01705        switch( ii ){
01706         case  1: orients[0]= 'L'; orients[1]= 'R'; break;
01707         case -1: orients[0]= 'R'; orients[1]= 'L'; break;
01708         case  2: orients[0]= 'P'; orients[1]= 'A'; break;
01709         case -2: orients[0]= 'A'; orients[1]= 'P'; break;
01710         case  3: orients[0]= 'I'; orients[1]= 'S'; break;
01711         case -3: orients[0]= 'S'; orients[1]= 'I'; break;
01712         default: orients[0]='\0'; orients[1]='\0'; break;
01713        }
01714 
01715        /* y-axis orientation */
01716        /* jj determines which spatial direction is y-axis  */
01717        /* and is the direction that has the biggest change */
01718        /* between the BRHC and TRHC                        */
01719 
01720        dx = fabs(xyz[6]-xyz[3]) ; jj = 1 ;
01721        dy = fabs(xyz[7]-xyz[4]) ; if( dy > dx ){ jj=2; dx=dy; }
01722        dz = fabs(xyz[8]-xyz[5]) ; if( dz > dx ){ jj=3;        }
01723        dx = xyz[jj+5]-xyz[jj+2] ; if( dx < 0. ){ jj = -jj;    }
01724        switch( jj ){
01725          case  1: orients[2] = 'L'; orients[3] = 'R'; break;
01726          case -1: orients[2] = 'R'; orients[3] = 'L'; break;
01727          case  2: orients[2] = 'P'; orients[3] = 'A'; break;
01728          case -2: orients[2] = 'A'; orients[3] = 'P'; break;
01729          case  3: orients[2] = 'I'; orients[3] = 'S'; break;
01730          case -3: orients[2] = 'S'; orients[3] = 'I'; break;
01731          default: orients[2] ='\0'; orients[3] ='\0'; break;
01732        }
01733 
01734        orients[4] = '\0' ;   /* terminate orientation string */
01735 
01736        kk = 6 - abs(ii)-abs(jj) ;   /* which spatial direction is z-axis   */
01737                                     /* where 1=LR, 2=PA, 3=IS               */
01738                                     /* (can't tell orientation from 1 slice) */
01739 
01740        zz = xyz[kk-1] ;             /* z-coordinate of this slice */
01741 
01742        hi->zoff = zz ;
01743        strcpy(hi->orients,orients) ;
01744 
01745        /* similarly (with zoff), store x and y origins in ge_extras */
01746        /*                                       2003 Jun 25 [rickr] */
01747        fp->gex.xorg = xyz[abs(ii)-1];
01748        fp->gex.yorg = xyz[abs(jj)-1];
01749 
01750        /*-- get TR in seconds --*/
01751 
01752        fseek( imfile , hdroff+194 , SEEK_SET ) ;
01753        fread( &itr , 4,1 , imfile ) ; /* note itr is an int */
01754        if( swap ) swap_4(&itr) ;
01755        hi->tr = 1.0e-6 * itr ;        /* itr is in microsec */
01756 
01757        /*-- get TE in milliseconds --*/
01758 
01759        fseek( imfile , hdroff+202 , SEEK_SET ) ;
01760        fread( &itr , 4,1 , imfile ) ; /* itr is an int, in microsec */
01761        if( swap ) swap_4(&itr) ;
01762        hi->te = 1.0e-6 * itr ;
01763 
01764        /* zmodify: get User Variable 17, a likely indicator of a new scan,
01765         * info by S. Marrett, location from S. Inati's matlab function
01766         * GE_readHeaderImage.m
01767         */
01768 
01769         /* printf ("\nuv17 = \n"); */
01770         fseek ( imfile , hdroff+272+202, SEEK_SET ) ;
01771         fread( &uv17 , 4, 1 , imfile ) ;
01772         if( swap ) swap_4(&uv17) ;
01773         /* printf ("%d ", (int)uv17);  */
01774         hi->uv17 = (int)uv17; 
01775         /* printf ("\n"); */
01776 
01777         /* store the ge_extra info */
01778         fp->gex.bpp    = bpp;
01779         fp->gex.cflag  = cflag;
01780         fp->gex.hdroff = hdroff;
01781         fp->gex.skip   = skip;
01782         fp->gex.swap   = swap;
01783         fp->gex.kk     = kk;
01784 
01785         memcpy( fp->gex.xyz, xyz, sizeof(xyz) );
01786         
01787         hi->good = 1 ;                  /* this is a good file */
01788 
01789     } /* end of actually reading image header */
01790 
01791     /* read image in as well */
01792     if ( get_image )
01793     {
01794         int elements = hi->nx * hi->ny;
01795 
01796         fp->bytes = elements * 2;                       /* bpp == 16 */
01797 
01798         if ( need_memory )
01799             fp->image = malloc( fp->bytes );
01800 
01801         if ( fp->image == NULL )
01802         {
01803             fprintf(stderr, "** RGI: no memory for %d byte image\n", fp->bytes);
01804             hi->good = 0;
01805             return -1;
01806         }
01807 
01808         fseek ( imfile, skip, SEEK_SET );
01809         if ( fread( fp->image , 2, elements, imfile ) != elements )
01810         {
01811             fprintf( stderr, "** RGI: failed to read %d shorts from %s\n",
01812                      elements, pathname );
01813             hi->good = 0;               /* signal file problem */
01814             return -1;
01815         }
01816     }
01817 
01818     fclose(imfile);
01819     return 0;
01820 }
01821 
01822 
01823 /*------------------------------------------------------------
01824  * Reverse the order of the 4 bytes at this address.
01825  *------------------------------------------------------------
01826 */
01827 static int swap_4( void * ptr )            /* destructive */
01828 {
01829     unsigned char * addr = ptr;
01830 
01831     addr[0] ^= addr[3]; addr[3] ^= addr[0]; addr[0] ^= addr[3];
01832     addr[1] ^= addr[2]; addr[2] ^= addr[1]; addr[1] ^= addr[2];
01833 
01834     return 0;
01835 }
01836 
01837 
01838 /*------------------------------------------------------------
01839  * print out the contents of the im_store_t struct
01840  *------------------------------------------------------------
01841 */
01842 static int idisp_im_store_t( char * info, im_store_t * is )
01843 {
01844     if ( info )
01845         fputs( info, stdout );
01846 
01847     if ( is == NULL )
01848     {
01849         printf( "idisp_im_store_t: is == NULL\n" );
01850         return -1;
01851     }
01852 
01853     printf( "im_store_t struct at %p :\n"
01854             "   (nalloc, nused)    = (%d, %d)\n"
01855             "   (ary_len, im_size) = (%d, %d)\n"
01856             "   (im_ary, x_im)     = (%p, %p)\n",
01857             is, is->nalloc, is->nused,
01858             is->ary_len, is->im_size, is->im_ary, is->x_im );
01859 
01860     return 0;
01861 }
01862 
01863 
01864 /*------------------------------------------------------------
01865  * print out the contents of the param_t struct
01866  *------------------------------------------------------------
01867 */
01868 static int idisp_hf_param_t( char * info, param_t * p )
01869 {
01870     if ( info )
01871         fputs( info, stdout );
01872 
01873     if ( p == NULL )
01874     {
01875         printf( "idisp_hf_param_t: p == NULL\n" );
01876         return -1;
01877     }
01878 
01879     printf( "param_t struct at %p :\n"
01880             "   ftype             =%d\n"
01881             "   (nused, nalloc)   = (%d, %d)\n"
01882             "   flist             = %p\n"
01883             "   glob_dir          = %s\n"
01884             "   nfiles            = %d\n"
01885             "   fnames            = %p\n",
01886             p, p->ftype, p->nused, p->nalloc, p->flist,
01887             CHECK_NULL_STR(p->glob_dir),
01888             p->nfiles, p->fnames );
01889 
01890     return 0;
01891 }
01892 
01893 
01894 /*------------------------------------------------------------
01895  * print out the contents of the opts_t struct
01896  *------------------------------------------------------------
01897 */
01898 static int idisp_hf_opts_t( char * info, opts_t * opt )
01899 {
01900     if ( info )
01901         fputs( info, stdout );
01902 
01903     if ( opt == NULL )
01904     {
01905         printf( "idisp_hf_opts_t: opt == NULL\n" );
01906         return -1;
01907     }
01908 
01909     printf( "opts_t struct at %p :\n"
01910             "   start_file         = %s\n"
01911             "   start_dir          = %s\n"
01912             "   sp                 = %s\n"
01913             "   gert_outdir        = %s\n"
01914             "   (argv, argc)       = (%p, %d)\n"
01915             "   (nt, nice)         = (%d, %d)\n"
01916             "   (debug, gert_reco) = (%d, %d)\n"
01917             "   quit               = %d\n"
01918             "   (rt, swap, rev_bo) = (%d, %d, %d)\n"
01919             "   host               = %s\n"
01920             "   drive_list(u,a,p)  = %d, %d, %p\n"
01921             "   rt_list   (u,a,p)  = %d, %d, %p\n",
01922             opt,
01923             CHECK_NULL_STR(opt->start_file),
01924             CHECK_NULL_STR(opt->start_dir),
01925             CHECK_NULL_STR(opt->sp),
01926             CHECK_NULL_STR(opt->gert_outdir),
01927             opt->argv, opt->argc,
01928             opt->nt, opt->nice,
01929             opt->debug, opt->gert_reco, opt->quit,
01930             opt->rt, opt->swap, opt->rev_bo,
01931             CHECK_NULL_STR(opt->host),
01932             opt->drive_list.nused, opt->drive_list.nalloc, opt->drive_list.str,
01933             opt->rt_list.nused, opt->rt_list.nalloc, opt->rt_list.str
01934             );
01935 
01936     return 0;
01937 }
01938 
01939 
01940 /*------------------------------------------------------------
01941  * print out the contents of the vol_t struct
01942  *------------------------------------------------------------
01943 */
01944 static int idisp_hf_vol_t( char * info, vol_t * v )
01945 {
01946     if ( info )
01947         fputs( info, stdout );
01948 
01949     if ( v == NULL )
01950     {
01951         printf( "idisp_hf_vol_t: v == NULL\n" );
01952         return -1;
01953     }
01954 
01955     printf( "vol_t struct at %p :\n"
01956             "   nim                 = %d\n"
01957             "   (fl_1, fn_1, fn_n)  = (%d, %d, %d)\n"
01958             "   first_file          = %s\n"
01959             "   last_file           = %s\n"
01960             "   (z_first, z_last)   = (%f, %f)\n"
01961             "   z_delta             = %f\n"
01962             "   (seq_num, run)      = (%d, %d)\n",
01963             v, v->nim, v->fl_1, v->fn_1, v->fn_n,
01964             v->first_file, v->last_file,
01965             v->z_first, v->z_last, v->z_delta,
01966             v->seq_num, v->run );
01967 
01968     idisp_ge_header_info( info, &v->geh );
01969     idisp_ge_extras( info, &v->gex );
01970 
01971     return 0;
01972 }
01973 
01974 
01975 /*------------------------------------------------------------
01976  *  Display the contents of the ge_extras struct.
01977  *  (copied from file_tool.c)
01978  *------------------------------------------------------------
01979 */
01980 static int idisp_ge_extras( char * info, ge_extras * E )
01981 {
01982     if ( info )
01983         fputs( info, stdout );
01984 
01985     if ( E == NULL )
01986     {
01987         printf( "idisp_ge_extras: E == NULL\n" );
01988         return -1;
01989     }
01990 
01991     printf( "ge_extras at %p :\n"
01992             "    bpp              = %d\n"
01993             "    cflag            = %d\n"
01994             "    hdroff           = %d\n"
01995             "    skip             = %d\n"
01996             "    swap             = %d\n"
01997             "    kk               = %d\n"
01998             "    xorg             = %f\n"
01999             "    yorg             = %f\n"
02000             "    (xyz0,xyz1,xyz2) = (%f,%f,%f)\n"
02001             "    (xyz3,xyz4,xyz5) = (%f,%f,%f)\n"
02002             "    (xyz6,xyz7,xyz8) = (%f,%f,%f)\n",
02003             E, E->bpp, E->cflag, E->hdroff, E->skip, E->swap, E->kk,
02004             E->xorg,   E->yorg,
02005             E->xyz[0], E->xyz[1], E->xyz[2],
02006             E->xyz[3], E->xyz[4], E->xyz[5],
02007             E->xyz[6], E->xyz[7], E->xyz[8]
02008           );
02009     return 0;
02010 }
02011 
02012 /*------------------------------------------------------------
02013  *  Display the contents of the ge_header_info struct.
02014  *  (copied from file_tool.c)
02015  *------------------------------------------------------------
02016 */
02017 static int idisp_ge_header_info( char * info, ge_header_info * I )
02018 {
02019     if ( info )
02020         fputs( info, stdout );
02021 
02022     if ( I == NULL )
02023     {
02024         printf( "idisp_ge_header_info: I == NULL\n" );
02025         return -1;
02026     }
02027 
02028     printf( "ge_header_info at %p :\n"
02029             "    good        = %d\n"
02030             "    (nx,ny)     = (%d,%d)\n"
02031             "    uv17        = %d\n"
02032             "    (dx,dy,dz)  = (%f,%f,%f)\n"
02033             "    zoff        = %f\n"
02034             "    (tr,te)     = (%f,%f)\n"
02035             "    orients     = %-8s\n",
02036             I, I->good, I->nx, I->ny, I->uv17,
02037             I->dx, I->dy, I->dz, I->zoff, I->tr, I->te,
02038             CHECK_NULL_STR(I->orients)
02039           );
02040 
02041     return 0;
02042 }
02043 
02044 /*----------------------------------------------------------------------
02045  * usage 
02046  *----------------------------------------------------------------------
02047 */
02048 static int usage ( char * prog, int level )
02049 {
02050     if ( level == IFM_USE_SHORT )
02051     {
02052         fprintf( stderr,
02053             "usage: %s [options] -start_dir DIR\n"
02054             "usage: %s -help\n",
02055             prog, prog );
02056         return 0;
02057     }
02058     else if ( level == IFM_USE_LONG )
02059     {
02060         printf(
02061           "\n"
02062           "%s - monitor real-time acquisition of I-files\n"
02063           "\n"
02064           "    This program is intended to be run during a scanning session\n"
02065           "    on a GE scanner, to monitor the collection of I-files.  The\n"
02066           "    user will be notified of any missing slice or any slice that\n"
02067           "    is aquired out of order.\n"
02068           "\n"
02069           "    It is recommended that the user runs '%s' just after the\n"
02070           "    scanner is first prepped, and then watches for error messages\n"
02071           "    during the scanning session.  The user should terminate the\n"
02072           "    program whey they are done with all runs.\n"
02073           "\n"
02074           "    Note that '%s' can also be run separate from scanning, either\n"
02075           "    to verify the integrity of I-files, or to create a GERT_Reco2\n"
02076           "    script, which is used to create AFNI datasets.\n"
02077           "\n"
02078           "    At the present time, the user must use <ctrl-c> to terminate\n"
02079           "    the program.\n"
02080           "\n"
02081           "  ---------------------------------------------------------------\n"
02082           "  usage: %s [options] -start_dir DIR\n"
02083           "\n"
02084           "  ---------------------------------------------------------------\n"
02085           "  examples (no real-time options):\n"
02086           "\n"
02087           "    %s -start_dir 003\n"
02088           "    %s -help\n"
02089           "    %s -start_dir 003 -GERT_reco2 -quit\n"
02090           "    %s -start_dir 003 -nt 120 -start_file 043/I.901\n"
02091           "    %s -debug 2 -nice 10 -start_dir 003\n"
02092           "\n"
02093           "  examples (with real-time options):\n"
02094           "\n"
02095           "    %s -start_dir 003 -rt\n"
02096           "    %s -start_dir 003 -rt -host pickle\n"
02097           "    %s -start_dir 003 -nt 120 -rt -host pickle\n"
02098           "\n"
02099           "  ** detailed real-time example:\n"
02100           "\n"
02101           "    This example scans data starting from directory 003, expects\n"
02102           "    160 repetitions (TRs), and invokes the real-time processing,\n"
02103           "    sending data to a computer called some.remote.computer.name\n"
02104           "    (where afni is running, and which considers THIS computer to\n"
02105           "    be trusted - see the AFNI_TRUSTHOST environment variable).\n"
02106           "\n"
02107           "    Multiple DRIVE_AFNI commands are passed through '-drive_afni'\n"
02108           "    options, one requesting to open an axial image window, and\n"
02109           "    another requesting an axial graph, with 160 data points.\n"
02110           "\n"
02111           "    See README.driver for acceptable DRIVE_AFNI commands.\n"
02112           "\n"
02113           "    Also, multiple commands specific to the real-time plugin are\n"
02114           "    passed via the '-rt_cmd' options.  The 'REFIX command sets the\n"
02115           "    prefix for the datasets output by afni.  The GRAPH_XRANGE and\n"
02116           "    GRAPH_YRANGE commands set the graph dimensions for the 3D\n"
02117           "    motion correction graph (only).  And the GRAPH_EXPR command\n"
02118           "    is used to replace the 6 default motion correction graphs with\n"
02119           "    a single graph, according to the given expression, the square\n"
02120           "    root of the average squared entry of the 3 rotaion parameters,\n"
02121           "    roll, pitch and yaw, ignoring the 3 shift parameters, dx, dy\n"
02122           "    and dz.\n"
02123           "\n"
02124           "    See README.realtime for acceptable DRIVE_AFNI commands.\n"
02125           "\n"
02126           "    %s                                                   \\\n"
02127           "       -start_dir 003                                      \\\n"
02128           "       -nt 160                                             \\\n"
02129           "       -rt                                                 \\\n"
02130           "       -host some.remote.computer.name                     \\\n"
02131           "       -drive_afni 'OPEN_WINDOW axialimage'                \\\n"
02132           "       -drive_afni 'OPEN_WINDOW axialgraph pinnum=160'     \\\n"
02133           "       -rt_cmd 'PREFIX eat.more.cheese'                    \\\n"
02134           "       -rt_cmd 'GRAPH_XRANGE 160'                          \\\n"
02135           "       -rt_cmd 'GRAPH_YRANGE 1.02'                         \\\n"
02136           "       -rt_cmd 'GRAPH_EXPR sqrt((d*d+e*e+f*f)/3)'            \n"
02137           "\n"
02138           "  ---------------------------------------------------------------\n"
02139           "  notes:\n"
02140           "\n"
02141           "    - Once started, this program exits only when a fatal error\n"
02142           "      occurs (single missing or out of order slices are not\n"
02143           "      considered fatal).\n"
02144           "\n"
02145           "      ** This has been modified.  The '-quit' option tells Imon\n"
02146           "         to terminate once it runs out of new data to use.\n"
02147           "\n"
02148           "    - To terminate this program, use <ctrl-c>.\n"
02149           "\n"
02150           "  ---------------------------------------------------------------\n"
02151           "  main option:\n"
02152           "\n"
02153           "    -start_dir DIR     : (REQUIRED) specify starting directory\n"
02154           "\n"
02155           "        e.g. -start_dir 003\n"
02156           "\n"
02157           "        The starting directory, DIR, must be of the form 00n,\n"
02158           "        where n is a digit.  The program then monitors all\n"
02159           "        directories of the form ??n, created by the GE scanner.\n"
02160           "\n"
02161           "        For instance, with the option '-start_dir 003', this\n"
02162           "        program watches for new directories 003, 023, 043, etc.\n"
02163           "\n"
02164           "  ---------------------------------------------------------------\n"
02165           "  real-time options:\n"
02166           "\n"
02167           "    -rt                : specify to use the real-time facility\n"
02168           "\n"
02169           "        With this option, the user tells '%s' to use the real-time\n"
02170           "        facility, passing each volume of images to an existing\n"
02171           "        afni process on some machine (as specified by the '-host'\n"
02172           "        option).  Whenever a new volume is aquired, it will be\n"
02173           "        sent to the afni program for immediate update.\n"
02174           "\n"
02175           "        Note that afni must also be started with the '-rt' option\n"
02176           "        to make use of this.\n"
02177           "\n"
02178           "        Note also that the '-host HOSTNAME' option is not required\n"
02179           "        if afni is running on the same machine.\n"
02180           "\n"
02181           "    -drive_afni CMND   : send 'drive afni' command, CMND\n"
02182           "\n"
02183           "        e.g.  -drive_afni 'OPEN_WINDOW axialimage'\n"
02184           "\n"
02185           "        This option is used to pass a single DRIVE_AFNI command\n"
02186           "        to afni.  For example, 'OPEN_WINDOW axialimage' will open\n"
02187           "        such an axial view window on the afni controller.\n"
02188           "\n"
02189           "        Note: the command 'CMND' must be given in quotes, so that\n"
02190           "              the shell will send it as a single parameter.\n"
02191           "\n"
02192           "        Note: this option may be used multiple times.\n"
02193           "\n"
02194           "        See README.driver for more details.\n"
02195           "\n"
02196           "    -host HOSTNAME     : specify the host for afni communication\n"
02197           "\n"
02198           "        e.g.  -host mycomputer.dot.my.network\n"
02199           "        e.g.  -host 127.0.0.127\n"
02200           "        e.g.  -host mycomputer\n"
02201           "        the default host is 'localhost'\n"
02202           "\n"
02203           "        The specified HOSTNAME represents the machine that is\n"
02204           "        running afni.  Images will be sent to afni on this machine\n"
02205           "        during the execution of '%s'.\n"
02206           "\n"
02207           "        Note that the enviroment variable AFNI_TRUSTHOST must be\n"
02208           "        set on the machine running afni.  Set this equal to the\n"
02209           "        name of the machine running Imon (so that afni knows to\n"
02210           "        accept the data from the sending machine).\n"
02211           "\n"
02212           "    -rev_byte_order   : pass the reverse of the BYTEORDER to afni\n"
02213           "\n"
02214           "        Reverse the byte order that is given to afni.  In case the\n"
02215           "        detected byte order is not what is desired, this option\n"
02216           "        can be used to reverse it.\n"
02217           "\n"
02218           "        See the (obsolete) '-swap' option for more details.\n"
02219           "\n"
02220           "    -rt_cmd COMMAND   : send COMMAND(s) to realtime plugin\n"
02221           "\n"
02222           "        e.g.  -rt_cmd 'GRAPH_XRANGE 120'\n"
02223           "        e.g.  -rt_cmd 'GRAPH_XRANGE 120 \\n GRAPH_YRANGE 2.5'\n"
02224           "\n"
02225           "        This option is used to pass commands to the realtime\n"
02226           "        plugin.  For example, 'GRAPH_XRANGE 120' will set the\n"
02227           "        x-scale of the motion graph window to 120 (repetitions).\n"
02228           "\n"
02229           "        Note: the command 'COMMAND' must be given in quotes, so\n"
02230           "        that the shell will send it as a single parameter.\n"
02231           "\n"
02232           "        Note: this option may be used multiple times.\n"
02233           "\n"
02234           "        See README.realtime for more details.\n"
02235           "\n"
02236           "    -swap  (obsolete) : swap data bytes before sending to afni\n"
02237           "\n"
02238           "        Since afni may be running on a different machine, the byte\n"
02239           "        order may differ there.  This option will force the bytes\n"
02240           "        to be reversed, before sending the data to afni.\n"
02241           "\n"
02242           "        ** As of version 3.0, this option should not be necessary.\n"
02243           "           '%s' detects the byte order of the image data, and then\n"
02244           "           passes that information to afni.  The realtime plugin\n"
02245           "           will (now) decide whether to swap bytes in the viewer.\n"
02246           "\n"
02247           "           If for some reason the user wishes to reverse the order\n"
02248           "           from what is detected, '-rev_byte_order' can be used.\n"
02249           "\n"
02250           "    -zorder ORDER     : slice order over time\n"
02251           "\n"
02252           "        e.g. -zorder alt\n"
02253           "        e.g. -zorder seq\n"
02254           "        the default is 'alt'\n"
02255           "\n"
02256           "        This options allows the user to alter the slice\n"
02257           "        acquisition order in real-time mode, simliar to the slice\n"
02258           "        pattern of the '-sp' option.  The main differences are:\n"
02259           "            o  only two choices are presently available\n"
02260           "            o  the syntax is intentionally different (from that\n"
02261           "               of 'to3d' or the '-sp' option)\n"
02262           "\n"
02263           "        ORDER values:\n"
02264           "            alt   : alternating in the Z direction (over time)\n"
02265           "            seq   : sequential in the Z direction (over time)\n"
02266           "\n"
02267           "  ---------------------------------------------------------------\n"
02268           "  other options:\n"
02269           "\n"
02270           "    -debug LEVEL       : show debug information during execution\n"
02271           "\n"
02272           "        e.g.  -debug 2\n"
02273           "        the default level is 1, the domain is [0,3]\n"
02274           "        the '-quiet' option is equivalent to '-debug 0'\n"
02275           "\n"
02276           "    -help              : show this help information\n"
02277           "\n"
02278           "    -hist              : display a history of program changes\n"
02279           "\n"
02280           "    -nice INCREMENT    : adjust the nice value for the process\n"
02281           "\n"
02282           "        e.g.  -nice 10\n"
02283           "        the default is 0, and the maximum is 20\n"
02284           "        a superuser may use down to the minimum of -19\n"
02285           "\n"
02286           "        A positive INCREMENT to the nice value of a process will\n"
02287           "        lower its priority, allowing other processes more CPU\n"
02288           "        time.\n"
02289           "\n"
02290           "    -nt VOLUMES_PER_RUN : set the number of time points per run\n"
02291           "\n"
02292           "        e.g.  -nt 120\n"
02293           "\n"
02294           "        With this option, if a run stalls before the specified\n"
02295           "        VOLUMES_PER_RUN is reached (notably including the first\n"
02296           "        run), the user will be notified.\n"
02297           "\n"
02298           "        Without this option, %s will compute the expected number\n"
02299           "        of time points per run based on the first run (and will\n"
02300           "        allow the value to increase based on subsequent runs).\n"
02301           "        Therefore %s would not detect a stalled first run.\n"
02302           "\n"
02303           "    -quiet             : show only errors and final information\n"
02304           "\n"
02305           "    -quit              : quit when there is no new data\n"
02306           "\n"
02307           "        With this option, the program will terminate once a delay\n"
02308           "        in new data occurs.  This is most appropriate to use when\n"
02309           "        the image files have already been collected.\n"
02310           "\n"
02311           "    -start_file S_FILE : have %s process starting at S_FILE\n"
02312           "\n"
02313           "        e.g.  -start_file 043/I.901\n"
02314           "\n"
02315           "        With this option, any earlier I-files will be ignored\n"
02316           "        by %s.  This is a good way to start processing a later\n"
02317           "        run, if it desired not to look at the earlier data.\n"
02318           "\n"
02319           "        In this example, all files in directories 003 and 023\n"
02320           "        would be ignored, along with everything in 043 up through\n"
02321           "        I.900.  So 043/I.901 might be the first file in run 2.\n"
02322           "\n"
02323           "    -version           : show the version information\n"
02324           "\n"
02325           "  ---------------------------------------------------------------\n"
02326           "  GERT_Reco2 options:\n"
02327           "\n"
02328           "    -GERT_Reco2        : output a GERT_Reco2 script\n"
02329           "\n"
02330           "        Create a script called 'GERT_Reco2', similar to the one\n"
02331           "        that Ifile creates.  This script may be run to create the\n"
02332           "        AFNI datasets corresponding to the I-files.\n"
02333           "\n"
02334           "    -gert_outdir OUTPUT_DIR  : set output directory in GERT_Reco2\n"
02335           "\n"
02336           "        e.g. -gert_outdir subject_A7\n"
02337           "        e.g. -od subject_A7\n"
02338           "        the default is '-gert_outdir afni'\n"
02339           "\n"
02340           "        This will add '-od OUTPUT_DIR' to the @RenamePanga command\n"
02341           "        in the GERT_Reco2 script, creating new datasets in the\n"
02342           "        OUTPUT_DIR directory, instead of the 'afni' directory.\n"
02343           "\n"
02344           "    -sp SLICE_PATTERN  : set output slice pattern in GERT_Reco2\n"
02345           "\n"
02346           "        e.g. -sp alt-z\n"
02347           "        the default is 'alt+z'\n"
02348           "\n"
02349           "        This options allows the user to alter the slice\n"
02350           "        acquisition pattern in the GERT_Reco2 script.\n"
02351           "\n"
02352           "        See 'to3d -help' for more information.\n"
02353           "\n"
02354           "  ---------------------------------------------------------------\n"
02355           "\n"
02356           "  Author: R. Reynolds - %s\n"
02357           "\n"
02358           "                        (many thanks to R. Birn)\n"
02359           "\n",
02360           prog, prog, prog, prog,
02361           prog, prog, prog, prog, prog, prog, prog, prog, prog,
02362           prog, prog, prog, prog, prog, prog, prog,
02363           IFM_VERSION
02364         );
02365 
02366         return 0;
02367     }
02368     else if ( level == IFM_USE_HIST )
02369     {
02370         fputs( g_history, stdout );
02371         return 0;
02372     }
02373     else if ( level == IFM_USE_VERSION )
02374     {
02375         printf( "%s: %s, compile date: %s\n",
02376                 prog, IFM_VERSION, __DATE__ );
02377         return 0;
02378     }
02379 
02380     fprintf( stderr, "error: usage() called with illegal level <%d>\n", level );
02381 
02382     return -1;
02383 }
02384 
02385 
02386 /* ----------------------------------------------------------------------
02387  * signal handler
02388  * ----------------------------------------------------------------------
02389 */
02390 static void hf_signal( int signum )
02391 {
02392     switch ( signum )
02393     {
02394         default :
02395             fprintf( stderr, "\nError: received unknown signal, %d\n",
02396                      signum );
02397             break;
02398 
02399         case SIGINT  :
02400         case SIGTERM :
02401             show_run_stats( &gS );
02402             break;
02403     }
02404 
02405     exit(0);
02406 }
02407 
02408 
02409 /* ----------------------------------------------------------------------
02410  * set_volume_stats
02411  * ----------------------------------------------------------------------
02412 */
02413 static int set_volume_stats( param_t * p, stats_t * s, vol_t * v )
02414 {
02415     run_t * rp;           /* for a little speed, this will be called often */
02416 
02417     if ( v == NULL || v->seq_num < 0 || v->run < 0 )
02418     {
02419         fprintf( stderr, "failure: SVS - insufficient data\n\n" );
02420         idisp_hf_vol_t ( "-- VOLUME FAILURE INFO : ", v );
02421     }
02422 
02423     /* initialize the stats structure */
02424     if ( s->nalloc == 0 )
02425     {
02426         s->runs = (run_t *)calloc( IFM_STAT_ALLOC, sizeof(run_t) );
02427         if ( s->runs == NULL )
02428         {
02429             fprintf( stderr, "failure: cannot allocate space for run info\n" );
02430             return -1;
02431         }
02432 
02433         /* first time caller - fill initial stats info */
02434         s->slices  = v->nim;
02435         s->z_first = v->z_first;
02436         s->z_last  = v->z_last;
02437         s->z_delta = v->z_delta;
02438 
02439         s->nalloc  = IFM_STAT_ALLOC;
02440         s->nused   = 0;
02441         s->nvols   = gP.opts.nt;        /* init with any user input value */
02442 
02443         if ( gD.level > 1 )
02444             fprintf( stderr, "\n-- svs: init alloc - vol %d, run %d, file %s\n",
02445                      v->seq_num, v->run, v->first_file );
02446     }
02447 
02448     if ( v->run >= s->nalloc )          /* run is 0-based */
02449     {
02450         /* make space for many more runs - we don't want to do this often */
02451         s->runs = (run_t *)realloc( s->runs, (v->run + IFM_STAT_ALLOC) *
02452                                              sizeof(run_t) );
02453         if ( s->runs == NULL )
02454         {
02455             fprintf( stderr, "failure: cannot realloc space for run info\n" );
02456             return -1;
02457         }
02458 
02459         s->nalloc = v->run + IFM_STAT_ALLOC;
02460 
02461         /* zero out any new memory */
02462         memset( s->runs + s->nused, 0, (s->nalloc - s->nused)*sizeof(run_t) );
02463 
02464         if ( gD.level > 1 )
02465             fprintf( stderr,
02466                 "\n-- svs: realloc (%d entries) - vol %d, run %d, file %s\n",
02467                 s->nalloc, v->seq_num, v->run, v->first_file );
02468 
02469     }
02470 
02471     /* we have memory - the current run number is an index into runs */
02472 
02473     rp = s->runs + v->run;
02474 
02475     if ( s->nused < v->run+1 )
02476         s->nused = v->run+1;
02477 
02478     if ( rp->volumes == 0 )
02479         strncpy( rp->f1name, v->first_file, IFM_MAX_FLEN );
02480 
02481     rp->volumes = v->seq_num;
02482 
02483     /* update nvols (if the user did not specify it and it is small) */
02484     if ( (p->opts.nt <= 0) && (s->nvols < v->seq_num) )
02485         s->nvols = v->seq_num;
02486 
02487     if ( gD.level > 2 )
02488         fprintf( stderr, "\n-- svs: run %d, seq_num %d\n", v->run, v->seq_num );
02489 
02490     return 0;
02491 }
02492 
02493 
02494 /* ----------------------------------------------------------------------
02495  * Create a gert_reco script.
02496  *
02497  * Note - stats struct parameters have been checked.
02498  * ----------------------------------------------------------------------
02499 */
02500 static int create_gert_script( stats_t * s, opts_t * opts )
02501 {
02502     FILE * fp;
02503     char * spat;                        /* slice acquisition pattern */
02504     char   cdir[4], csuff[IFM_SUFFIX_LEN];
02505     int    num_valid, c;
02506 
02507     /* if the user did not give a slice pattern string, use the default */
02508     spat = opts->sp ? opts->sp : IFM_SLICE_PAT;
02509 
02510     for ( c = 0, num_valid = 0; c < s->nused; c++ )
02511         if ( s->runs[c].volumes > 0 )
02512             num_valid++;
02513 
02514     if ( num_valid == 0 )
02515     {
02516         fprintf( stderr, "-- no runs to use for '%s'\n", IFM_GERT_SCRIPT );
02517         return 0;
02518     }
02519 
02520     if ( (fp = fopen( IFM_GERT_SCRIPT, "w" )) == NULL )
02521     {
02522         fprintf( stderr, "failure: cannot open '%s' for writing, "
02523                  "check permissions\n", IFM_GERT_SCRIPT );
02524         return -1;
02525     }
02526 
02527     /* output text casually, uh, borrowed from Ifile.c */
02528     fprintf( fp,
02529              "#!/bin/tcsh\n"
02530              "\n"
02531              "# This script was automatically generated by '%s'.\n"
02532              "# The script format was, uh, borrowed from Ziad's Ifile.c.\n"
02533              "#\n"
02534              "# Please modify the following options for your own evil uses.\n"
02535              "\n"
02536              "set OutlierCheck = '-oc'         # use '' to skip outlier check\n"
02537              "set OutPrefix    = 'OutBrick'    # prefix for datasets\n"
02538              "set OutputDir    = '-od %s'    # where to put output datasets\n"
02539              "\n"
02540              "\n",
02541              IFM_PROG_NAME,
02542              opts->gert_outdir ? opts->gert_outdir : "afni"
02543            );
02544 
02545     for ( c = 0; c < s->nused; c++ )
02546         if ( s->runs[c].volumes > 0 )
02547         {
02548             if ( path_to_dir_n_suffix(cdir, csuff, s->runs[c].f1name) < 0 )
02549             {
02550                 fclose( fp );
02551                 return -1;
02552             }
02553 
02554             fprintf( fp, "@RenamePanga %s %s %d %d $OutPrefix "
02555                          "-sp %s $OutlierCheck $OutputDir\n",
02556                      cdir, csuff, s->slices, s->runs[c].volumes, spat );
02557         }
02558 
02559     fputc( '\n', fp );
02560     fclose( fp );
02561 
02562     /* now make it an executable */
02563     system( "chmod u+x " IFM_GERT_SCRIPT );
02564 
02565     return 0;
02566 }
02567 
02568 
02569 /* ----------------------------------------------------------------------
02570  * - show statistics from the runs
02571  * - output any requested GERT_Reco2 file
02572  * ----------------------------------------------------------------------
02573 */
02574 static int show_run_stats( stats_t * s )
02575 {
02576     int c;
02577 
02578     if ( s == NULL )
02579     {
02580         fprintf( stderr, "failure, SRS - no stats struct!\n" );
02581         return -1;
02582     }
02583 
02584     if ( s->nalloc <= 0 || s->nused <= 0 )
02585         return 0;
02586 
02587     printf( "\n\n"
02588             "final run statistics:\n"
02589             "    volume info :\n"
02590             "        slices  : %d\n"
02591             "        z_first : %.4f\n"
02592             "        z_last  : %.4f\n"
02593             "        z_delta : %.4f\n"
02594             "\n",
02595             s->slices, s->z_first, s->z_last, s->z_delta );
02596 
02597     for ( c = 0; c < s->nused; c++ )
02598     {
02599         if ( s->runs[c].volumes > 0 )
02600             printf( "    run #%4d : volumes = %3d, first file = %s\n",
02601                     c, s->runs[c].volumes, s->runs[c].f1name );
02602     }
02603 
02604     putchar( '\n' );
02605 
02606     if ( gP.opts.gert_reco )
02607         (void)create_gert_script( s, &gP.opts );
02608 
02609     fflush( stdout );
02610 
02611     return 0;
02612 }
02613 
02614 
02615 /* ----------------------------------------------------------------------
02616  * given tr, compute a sleep time of approximate 2*TR
02617  * ----------------------------------------------------------------------
02618 */
02619 static int nap_time_from_tr( float tr )
02620 {
02621     float tr2 = 2 * tr;
02622 
02623     if ( tr2 < 1 )
02624         return 1;
02625 
02626     if ( tr2 > 10 )
02627         return 10;                      /* ??? tres big */
02628 
02629     return( (int)(tr2 + 0.9) );         /* basically, use ceiling */
02630 }
02631 
02632 
02633 /* ----------------------------------------------------------------------
02634  * find_next_zoff
02635  *
02636  * Given p->flist, search from index start for an image with
02637  * geh.zoff equal to zoff.
02638  *
02639  * return   index : upon succes         (start <= index <= p->nused)
02640  *             -1 : not found
02641  *             -2 : error
02642  * ----------------------------------------------------------------------
02643 */
02644 static int find_next_zoff( param_t * p, int start, float zoff )
02645 {
02646     int count;
02647 
02648     if ( (p == NULL) || (start < 0) )
02649         return -2;
02650 
02651     if ( start > p->nused )                     /* say not found */
02652         return -1;
02653 
02654     for ( count = start; count <= p->nused; count++ )
02655         if ( fabs( zoff - p->flist[count].geh.zoff ) < IFM_EPSILON )
02656             return count;                       /* found! */
02657 
02658     return -1;
02659 }
02660 
02661 
02662 /* ----------------------------------------------------------------------
02663  * Given:  run     > 0
02664  *         seq_num > 0
02665  *         naps
02666  *
02667  * If naps is too big, and the run is incomplete, print an obnoxious
02668  * warning message to the user.
02669  *
02670  * notes:   - print only 1 warning message per seq_num, per run
02671  *          - prev_run and prev_seq_num are for the previously found volume
02672  *
02673  * returns:
02674  *          2 : run is stalled - message printed
02675  *          1 : apparent end of a run
02676  *          0 : no stall, or if a message has already been printed
02677  *         -1 : function failure
02678  * ----------------------------------------------------------------------
02679 */
02680 static int check_stalled_run ( int run, int seq_num, int naps, int nap_time )
02681 {
02682     static int func_failure =  0;
02683     static int prev_run     = -1;
02684     static int prev_seq     = -1;
02685 
02686     if ( func_failure != 0 )
02687         return 0;
02688 
02689     if ( ( run < 1 ) || ( seq_num < 1 ) || ( naps <= IFM_MAX_RUN_NAPS ) )
02690         return 0;
02691 
02692     /* verify that we have already taken note of the previous volume */
02693     if ( (((gS.nused + 1) < run) || (gS.runs[run].volumes < seq_num)) &&
02694          ( func_failure == 0 ) )
02695     {
02696         fprintf( stderr, "** warning: CSR - stats inconsistancy!\n" );
02697         func_failure = 1;
02698 
02699         return -1;
02700     }
02701 
02702     if ( seq_num < gS.nvols )      /* are we done with the run yet? */
02703     {
02704         /* if we haven't printed before, this is the first stalled case */
02705         if ( (run != prev_run) || (seq_num != prev_seq) )
02706         {
02707             fprintf( stderr, "\007\n"
02708                      "****************************************************\n"
02709                      "Warning: run seems to be stalled\n"
02710                      "\n"
02711                      "    run                    : %d\n"
02712                      "    TRs completed          : %d (of %d)\n"
02713                      "    approximate idle time  : %d seconds\n"
02714                      "    first file of this run : %s\n"
02715                      "****************************************************\n",
02716                      run, seq_num, gS.nvols,
02717                      naps*nap_time, gS.runs[run].f1name );
02718 
02719             prev_run = run;
02720             prev_seq = seq_num;
02721 
02722             return 2;
02723         }
02724     }
02725     /* else (we are done) */
02726     else if ( (run != prev_run) || (seq_num != prev_seq) )
02727     {
02728         /* this is our first visit, note the fact */
02729         prev_run = run;
02730         prev_seq = seq_num;
02731 
02732         return 1;
02733     }
02734 
02735     return 0;
02736 }
02737 
02738 /*-------------------------------------------------------*/
02739 /*! Return the file length (-1 if file not found).       */
02740 /*  (local copy from thd_filestuff.c                     */
02741 
02742 static unsigned long l_THD_filesize( char * pathname )
02743 {
02744     static struct stat buf ; int ii ;
02745 
02746     if( pathname == NULL ) return -1 ;
02747         ii = stat( pathname , &buf ) ; if( ii != 0 ) return -1 ;
02748 
02749     return buf.st_size ;
02750 }
02751 
02752 /* ----------------------------------------------------------------------
02753  * Make sure im_ary has enough memory for num_images pointers.
02754  *
02755  * return  -1 : on error
02756  *          0 : nothing needed
02757  *          1 : memory successfully created
02758  * ----------------------------------------------------------------------
02759 */
02760 static int check_im_store_space( im_store_t * is, int num_images )
02761 {
02762     if ( (is == NULL) || (num_images <= 0) )
02763     {
02764         fprintf( stderr, "** CISS: invalid parameters (%p,%d)\n",
02765                  is, num_images );
02766         return -1;
02767     }
02768 
02769     if ( is->ary_len >= num_images )
02770         return 0;
02771 
02772     /* so we need memory */
02773 
02774     if ( gD.level > 2 )
02775         fprintf( stderr, "++ allocating %d image pointers (was %d)\n",
02776                  num_images, is->ary_len );
02777 
02778     is->im_ary = realloc(is->im_ary, num_images * sizeof(void *));
02779 
02780     if ( is->im_ary == NULL )
02781     {
02782         fprintf( stderr, "** failure: cannot allocate %d image pointers\n",
02783                  num_images );
02784         return -1;
02785     }
02786 
02787     is->ary_len = num_images;
02788 
02789     return 1;
02790 }
02791 
02792 
02793 /* ----------------------------------------------------------------------
02794  * Set the im_size and allocate memory for x_im.
02795  *
02796  * return  -1 : on error
02797  *          0 : success
02798  * ----------------------------------------------------------------------
02799 */
02800 static int alloc_x_im( im_store_t * is, int bytes )
02801 {
02802     if ( (is == NULL) || (bytes <= 0) )
02803     {
02804         fprintf( stderr, "** bad params to AXI (%p,%d)\n", is, bytes );
02805         return -1;
02806     }
02807 
02808     is->im_size = bytes;
02809 
02810     if ( (is->x_im = malloc( bytes )) == NULL )
02811     {
02812         fprintf( stderr, "** AXI: failed to malloc %d bytes for x_im\n",
02813                  bytes );
02814         return -1;
02815     }
02816 
02817     if ( gD.level > 1 )
02818         fprintf( stderr, "++ allocating %d bytes for is->x_im\n", bytes );
02819 
02820     return 0;
02821 }
02822 
02823 
02824 /* ----------------------------------------------------------------------
02825  * Determine the byte order of the image.
02826  *
02827  * Note our byte order (LSB_FIRST or MSB_FIRST).
02828  * If gex.swap is set, reverse it.  If user wants opposite, reverse it.
02829  *
02830  * return   0 : success
02831  *         -1 : on error
02832  * ----------------------------------------------------------------------
02833 */
02834 static int check_im_byte_order( int * order, vol_t * v, param_t * p )
02835 {
02836     int one = 1;
02837 
02838     if ( (order == NULL) || (v == NULL) || (p == NULL) )
02839     {
02840         fprintf( stderr, "** invalid paramters to CIBO (%p,%p,%p)\n",
02841                  order, v, p );
02842         return -1;
02843     }
02844 
02845     /* note the order for the current system */
02846     *order = (*(char *)&one == 1) ? LSB_FIRST : MSB_FIRST;
02847 
02848     if ( gD.level > 1 )
02849         fprintf( stderr, "-- system order is %s, ",
02850                  (*order == MSB_FIRST) ? "MSB_FIRST" : "LSB_FIRST" );
02851 
02852     /* are the images the opposite of this?  does the user want the opposite? */
02853     if ( p->flist[v->fl_1].gex.swap ^ p->opts.rev_bo )
02854         *order = LSB_FIRST + MSB_FIRST - *order;      /* for entertainment */
02855 
02856     if ( gD.level > 1 )
02857         fprintf( stderr, "image order is %s\n",
02858                  (*order == MSB_FIRST) ? "MSB_FIRST" : "LSB_FIRST" );
02859 
02860     return 0;
02861 }
02862 
02863 
02864 /* ----------------------------------------------------------------------
02865  * Use gex.kk to figure out the z orientation, and complete
02866  * the v->geh.orients string.
02867  *
02868  * orient(kk) = { LR, if kk = 1
02869  *              { PA, if kk = 2
02870  *              { IS, if kk = 3
02871  *
02872  * return   0 : success
02873  *         -1 : on error
02874  * ----------------------------------------------------------------------
02875 */
02876 static int complete_orients_str( vol_t * v, param_t * p )
02877 {
02878     int kk;
02879 
02880     if ( (v == NULL) || (p == NULL) )
02881     {
02882         fprintf( stderr, "** invalid paramters to COS (%p,%p)\n", v, p );
02883         return -1;
02884     }
02885 
02886     kk = p->flist[v->fl_1].gex.kk;
02887 
02888     switch( kk )
02889     {
02890         case 1:                                 /* LR */
02891             if ( v->z_delta > 0 )
02892             {
02893                 v->geh.orients[4] = 'L';
02894                 v->geh.orients[5] = 'R';
02895             }
02896             else
02897             {
02898                 v->geh.orients[4] = 'R';
02899                 v->geh.orients[5] = 'L';
02900             }
02901             break;
02902 
02903         case 2:                                 /* PA */
02904             if ( v->z_delta > 0 )
02905             {
02906                 v->geh.orients[4] = 'P';
02907                 v->geh.orients[5] = 'A';
02908             }
02909             else
02910             {
02911                 v->geh.orients[4] = 'A';
02912                 v->geh.orients[5] = 'P';
02913             }
02914             break;
02915             
02916         case 3:                                 /* IS */
02917             if ( v->z_delta > 0 )
02918             {
02919                 v->geh.orients[4] = 'I';
02920                 v->geh.orients[5] = 'S';
02921             }
02922             else
02923             {
02924                 v->geh.orients[4] = 'S';
02925                 v->geh.orients[5] = 'I';
02926             }
02927             break;
02928             
02929         default:
02930         {
02931             fprintf(stderr, "** COS failure: kk (%d) out of [1,3] range\n", kk);
02932             return -1;
02933         }
02934     }
02935 
02936     v->geh.orients[6] = '\0';
02937 
02938     return 0;
02939 }
02940 
02941 
02942 /* ----------------------------------------------------------------------
02943  * return the index of 'file' in the directory list
02944  *
02945  * return  -1   : failed to find it
02946  *         else : index
02947  * ----------------------------------------------------------------------
02948 */
02949 static int find_fl_file_index( param_t * p, char * file )
02950 {
02951     char ** nlp;
02952     int     index;
02953 
02954     if ( (p == NULL) || (file == NULL) )
02955         return 0;
02956 
02957     for ( index = 0, nlp = p->fnames; index < p->nfiles; index++, nlp++ )
02958         if ( ! strcmp( *nlp, file ) )
02959             return index;
02960 
02961     return -1;
02962 }
02963 
02964 /* ----------------------------------------------------------------------
02965  * return the number of occurances of 'target' in 'str' of length 'len'
02966  * ----------------------------------------------------------------------
02967 */
02968 static int str_char_count( char * str, int len, char target )
02969 {
02970     char * cp;
02971     char * last = str + len;
02972     int    num = 0;
02973 
02974     if ( (str == NULL) || (len <= 0) )
02975         return 0;
02976 
02977     for ( cp = str; cp < last; cp++ )
02978         if ( *cp == target )
02979             num++;
02980 
02981     return num;
02982 }
02983 
02984 
02985 /* ----------------------------------------------------------------------
02986  * Given path, find dir and suff.
02987  *
02988  * dir    - 3 character starting directory           (e.g. 003)
02989  * suff   - 10 char (max) trailing I-file suffix     (e.g. 017, for I.017)
02990  * path   - first file in run                        (e.g. 003/I.017)
02991  *
02992  * return  0 : success
02993  *        -1 : failure
02994  * ----------------------------------------------------------------------
02995 */
02996 static int path_to_dir_n_suffix( char * dir, char * suff, char * path )
02997 {
02998     char * cp, *cp2;
02999 
03000     if ( (dir == NULL) || (suff == NULL) || (path == NULL) )
03001     {
03002         fprintf( stderr, "failure: PTDNS - invalid params (%p,%p,%p)\n",
03003                  dir, suff, path );
03004         return -1;
03005     }
03006 
03007     /* find last '.' */
03008     for ( cp = path + strlen(path) - 1; (*cp != '.') && (cp > path); cp-- )
03009         ;
03010 
03011     if ( *cp != '.' )
03012     {
03013         fprintf( stderr, "failure: cannot find suffix in '%s'\n", path );
03014         return -1;
03015     }
03016     else if ( strlen( cp ) > IFM_SUFFIX_LEN )          /* '.' not included */
03017     {
03018         fprintf( stderr, "failure: suffix too long in '%s'\n", path );
03019         return -1;
03020     }
03021 
03022     strcpy( suff, cp+1 );               /* copy null-terminated suffix */
03023 
03024     /* make sure all characters are digits (treat as string, not int) */
03025     for ( cp2 = suff; (*cp2 != '\0') && isdigit(*cp2); cp2++ )
03026        ;
03027 
03028     if ( *cp2 != '\0' )
03029     {
03030         fprintf( stderr, "failure: suffix not integer in '%s'\n", path );
03031         return -1;
03032     }
03033 
03034     /* now get dir prefix - should be nnn/I.mmm */
03035     cp -= 5;
03036     if ( ( cp < path )          ||    /* we should have a directory here */
03037          ( ! isdigit( cp[0] ) ) ||    /* then 3 digits */
03038          ( ! isdigit( cp[1] ) ) ||
03039          ( ! isdigit( cp[2] ) ) ||
03040          (   cp[3] != '/'     ) ||
03041          (   cp[4] != 'I'     ) )
03042     {
03043         fprintf( stderr, "failure: PTDNS - ill-formed path '%s'\n", path );
03044         return -1;
03045     }
03046 
03047     /* we are set, just copy the data */
03048     strncpy( dir, cp, 3 );
03049     dir[3] = '\0';
03050 
03051     return 0;
03052 }
03053 
03054 
03055 /* ----------------------------------------------------------------------
03056  * Add given string (pointer) to list.                       v3.3 [rickr]
03057  *
03058  * return  0 : success
03059  *        -1 : failure (realloc)
03060  * ----------------------------------------------------------------------
03061 */
03062 static int add_to_string_list( string_list * list, char * str )
03063 {
03064     if ( !list || !str )
03065         return -1;
03066 
03067     /* if needed, just add 10 at a time to nalloc (they're only pointers) */
03068     if ( list->nalloc == 0 || (list->nalloc <= list->nused) )
03069     {
03070         list->nalloc += 10;
03071         list->str = (char **)realloc(list->str, list->nalloc*sizeof(char *));
03072         if ( !list->str )
03073         {
03074             fprintf(stderr,"** failed to allocate for %d (char *)s\n",
03075                     list->nalloc);
03076             return -1;
03077         }
03078     }
03079 
03080     list->str[list->nused] = str;
03081     list->nused++;
03082 
03083     return 0;
03084 }
03085 
03086 
03087 /* ----------------------------------------------------------------------
03088  * If free_mem, free memory.  Set contents as empty.         v3.3 [rickr]
03089  * ----------------------------------------------------------------------
03090 */
03091 static int empty_string_list( string_list * list, int free_mem )
03092 {
03093     if ( list->str && free_mem )
03094         free( list->str );
03095 
03096     list->str    = NULL;
03097     list->nalloc = 0;
03098     list->nused  = 0;
03099 
03100     return 0;
03101 }
03102 
 

Powered by Plone

This site conforms to the following standards: