/*********************************************************************** ident_x_tape.c ********************************************************************** Description: Parses the directory of a Patient data set and reports information about it. Contains the following modules: main() main driver for parsing exchange files read_tape_directory() Reads AAPM directory file from disk and parses the data into the appropriate data structures. next_entry() Parses all AAPM directory entries up to, but not including, the next image #. file_blocks() Counts the number of data blocks in an AAPM formatted file (assumes that buffered files are being used). check_open() Checks the length of an exchange file and opens it for reading. ********************************************************************** Revision History: Date Pgmr / Modification notes $Log: ident_x_tape.c,v $ * Revision 1.2 2000/01/19 16:59:50 jwm * initialize the seed count to zero * * Revision 1.1 2000/01/14 22:54:05 jwm * Remove comments originating in other development trees * * Revision 1.0 2000/01/14 15:55:56 jwm * Initial revision **********************************************************************/ /* Include Files */ #include #include #include #include #include #include #include #include #include #include #include "sitedata.h" #include "exchkeys.h" #include "patexchange.h" typedef struct beam_info_t { struct beam_info_t *next; /* POINTER TO NEXT ELEMENT IN LINKED LIST */ char *description; /* BEAM DESCRIPTION */ int beam_number; /* ORIGINATOR'S BEAM NUMBER */ int num_drrs; /* NUMBER OF DRR FILMS */ int num_films; /* NUMBER OF DIGITAL FILMS OTHER THAN DRR'S */ int num_tx; /* NUMBER OF TREATMENTS */ float dose_per_tx; /* DOSE (GY) PER TX */ float energy; /* BEAM ENERGY IN MV/MEV */ beam_modality_type mode; /* BEAM MODALITY */ int wedge_angle; /* WEDGE ANGLE */ } beam_info_t; typedef struct frac_list_t { struct frac_list_t *next; /* POINTER TO NEXT FRACTION GROUP */ char *fraction_group_id; /* FRACTION GROUP ID */ int num_beams; /* NUMBER OF BEAM IN THIS FRACTION GROUP */ beam_info_t *beam_list; /* LIST OF BEAMS WITH THIS FRACTION GROUP */ int num_doses; /* # OF DOSE FILES */ char *description; /* DESCRIPTION OF FRACTION GROUP (FROM DOSES) */ } frac_list_t; typedef struct seed_t { struct seed_t *next; /* Pointer to next seed plan */ seeddata_t seeddata; /* Seed data structure */ } seed_t; typedef struct dvh_names_t { struct dvh_names_t *next; /* NEXT POINTER IN LINKED LIST */ char *plan_id; /* PLAN ID OF ORIGIN */ char *struct_id; /* STRUCTURE ID */ int num_bins; /* NUMBER OF BINS FOR THIS STRUCTURE'S DVH */ } dvh_names_t; typedef struct datalist_t { char *patient_name; /* PATIENT NAME */ int case_number; /* CASE NUMBER */ int num_comms; /* NUMBER OF COMMENT FILES TO PROCESS */ int num_cts; /* NUMBER OF CT FILES TO BE PROCESSED */ int num_mr; /* NUMBER OF MR FILES TO PROCESSED */ int num_us; /* NUMBER OF US FILES TO PROCESSED */ int num_structs; /* NUMBER OF ANATOMIC STRUCTURES */ char **struct_ids; /* STRUCTURE ID'S */ int num_dvhs; /* # OF DVH FILES */ dvh_names_t *dvh_names; /* DVH STRUCTURE NAMES & PLANS */ int num_plans; /* NUMBER OF PLAN FILES TO PROCESS */ int plan_type; /* 0=NONE; 1=TELE; 2=SEED */ union { frac_list_t *tele; seed_t *seed; } plans; /* TELE OR SEED information */ } datalist_t; static frac_list_t *add_frac_group ( datalist_t *data_struct, /* DIRECTORY INFO STRUCTURE */ char *group_id /* FRACTION GROUP ID */ ); static beam_info_t *add_beam_list ( frac_list_t *frac_ptr, /* FRACTION INFORMATION POINTER */ int beam_number, /* BEAM NUMBER TO ADD */ char *description, /* BEAM DESCRIPTION */ int num_tx, /* # OF TREATMENTS */ float dose_per_tx, /* DOSE (GY) PER TX */ float energy, /* BEAM ENERGY IN MV/MEV */ beam_modality_type mode, /* BEAM MODALITY */ int wedge_angle /* WEDGE ANGLE */ ); static beam_info_t *locate_in_beam_list ( datalist_t *data_struct, /* DIRECTORY INFO STRUCTURE */ int beam_number /* BEAM NUMBER TO ADD */ ); /* GLOBAL FILE STREAM POINTER FOR LOG FILE */ FILE *aapm_log_file=NULL; char aapm_log_string[180]; /* RCS INFORMATION */ static char *RCSname = "$RCSfile: ident_x_tape.c,v $"; static char *RCSRev = "$Revision: 1.2 $"; static char *RCSDate = "$Date: 2000/01/19 16:59:50 $"; /***************************************************************************** main() **************************************************************************** Functional Description: Gives a brief description of the contents of an RTOG data exchange file set. It also checks the syntax of the directory and checks the existence of the data files. The command line is as follows: ident_x_tape where: ident_x_tape is the executable program name. is the directory in which the Patient Exchange format file reside. is the size of the data blocks in bytes (usually 2048). >>>>>>>>+<<<<<<<< >>>> WARNING <<<< >>>>>>>>+<<<<<<<< As of 27Sep99 this code assumes that tele and seed plans are not submitted in the same data set. ***************************************************************************/ void main ( int argc, /* COMMAND LINE ARGUMENT COUNT */ char *argv[] /* COMMAND LINE ARGUMENTS */ ) { char output_filename[PATH_MAX]; /* OUTPUT FILE NAME */ FILE *output; /* OUTPUT FILE STREAM POINTER */ tapedir_t tape; /* TAPE DIRECTORY STRUCTURE */ case_t *patcase; /* PATIENT CASE STRUCTURE */ char filename[PATH_MAX]; /* FILENAME STRING */ exch_file_t *file_list_ptr; /* FILE LIST POINTER */ int answer; /* ANSWER TO CONTINUE ON ERROR REQUEST */ char string[800]; /* TEMP TEXT STORAGE */ int num_comment; /* NUMBER OF COMMENT FILES */ int num_ct; /* NUMBER OF CT SCAN FILES */ int num_mr; /* NUMBER OF MR SCAN FILES */ int num_us; /* NUMBER OF US SCAN FILES */ int num_structs; /* NUMBER OF STRUCTURE FILES */ int num_beams; /* NUMBER OF BEAM GEOMETRY FILES */ int num_seed; /* NUMBER OF SEED GEOMETRY FILES */ int num_films; /* NUMBER OF FILMS FILES */ int num_doses; /* NUMBER OF DOSE FILES */ int num_dvh; /* NUMBER OF DVH FILES */ int missing_files; /* COUNT OF MISSING FILES */ typedef struct { struct string_list_t *next; /* POINTER TO NEXT LIST ENTRY */ char *entry; /* ERROR STRING ENTRY */ } string_list_t; string_list_t error_list; /* HEAD OF ERROR LIST */ string_list_t *err_list_ptr; /* ERROR LIST POINTER */ char file_type[80]; /* FILE TYPE OF FILE BEING CHECKED */ int i, j, k; /* LOOP COUNTER */ datalist_t data_struct; frac_list_t *frac_ptr; /* POINTER TO CURRENT FRACTION GROUP STRUCT */ beam_info_t *beam_ptr; /* CURRENT LIST ENTRY */ dvh_names_t *dvh_ptr; /* POINTER TO DVH DATA */ int arg_found; /* FLAG FOR LEGITIMATE COMMAND LINE SWITCH */ struct stat statbuf; /* FOR STATING FILES */ typedef struct { char *long_switch; /* LONG FLAG */ char *short_switch; /* SHORT FLAG */ char *descrip; /* BRIEF DESCRIPTION OF FLAG */ } option_t; typedef enum { eOPT_DIR, eOPT_BLOCK_SIZE, eOPT_STD_FILE_NAME, eOPT_OUTPUT_FILE_NAME, eOPT_HELP } option_type; option_t options[] = { {"-dir", "-d", "usage (opt): -d "}, {"-block", "-b", "usage (opt): -b "}, {"-std", "-s", "usage (opt): -s use standard file name convention"}, {"-out", "-o", "usage (opt): -o "}, {"-help", "-h", "usage: -h prints help info and quits"} }; static int num_options = 5; /* NUMBER OF OPTIONS IN LIST */ static char *arg_strings[5]; /* STRINGS FOR ARGUMENTS */ /* CHECK AND PROCESS ARGUMENTS */ i=1; while (i < argc ) { for (j=0; j [-b -s] [-o ]\n" ); for ( k=0; k [-b -s] [-o ]\n" ); for ( k=0; k [-b -s] [-o ]\n" ); for ( k=0; kpatient_id = dup_string( argv[3] ); data_struct.case_number = patcase->case_number; data_struct.patient_name = dup_string( patcase->patient_name ); /* PROCESS THE (ONE AND ONLY) CASE */ /* SET THE PROCESSING FLAGS */ file_list_ptr = patcase->head_file; /* RESET THE COUNTS */ num_comment = num_ct = num_mr = num_us = num_structs = num_beams = num_seed = num_films = num_doses = num_dvh = 0; data_struct.plan_type = 0; /* clear the plan "type" */ while( file_list_ptr != NULL ) { /* EVALUATE THIS FILE */ switch( file_list_ptr->image_flag ) { case eCOMMENT: num_comment++; data_struct.num_comms++; sprintf( file_type, "COMMENT" ); break; case eCTSCAN: num_ct++; data_struct.num_cts++; sprintf( file_type, "CTSCAN" ); break; case eMRISCAN: num_mr++; data_struct.num_mr++; sprintf( file_type, "MRISCAN" ); break; case eUSSCAN: num_us++; data_struct.num_us++; sprintf( file_type, "USSCAN" ); break; case eSEEDGEOM: num_seed++; data_struct.plan_type = 2; /* mark this as a seed plan */ if ( (data_struct.plans.seed = calloc(1,sizeof(seed_t))) == NULL ) { fprintf( stderr, "\nError allocating seed_t structure\n" ); exit ( -1 ); } /* copy the seed directory information structure */ data_struct.plans.seed->seeddata = file_list_ptr->image.seeddata; break; case eSTRUCTURE: num_structs++; data_struct.num_structs++; if ( data_struct.num_structs == 1 ) { if ( (data_struct.struct_ids = (char **)calloc( (size_t)1, sizeof( char **))) == NULL ) { fprintf( stderr, "\nError allocating struct_id's list\n" ); exit ( -1 ); } } else { if ( (data_struct.struct_ids = (char **)realloc( (void *)data_struct.struct_ids, sizeof( char **) * data_struct.num_structs)) == NULL ) { fprintf( stderr, "\nError reallocating struct_id's list\n" ); exit ( -1 ); } } data_struct.struct_ids[data_struct.num_structs-1] = dup_string( file_list_ptr->image.structure.struct_name ); sprintf( file_type, "STRUCTURE (%s)", file_list_ptr->image.structure.struct_name ); break; case eBEAMGEOM: num_beams++; data_struct.plan_type = 1; /* mark this as a tele plan */ /* INCLUDE IN FRACTION GROUP LIST */ if ( (frac_ptr = add_frac_group( &data_struct, file_list_ptr->image.beam_geometry.fraction_group_id )) == NULL ) { fprintf( stderr, "\nError adding a fraction group\n" ); exit( -1 ); } /* ADD THE BEAM TO THE INFORMATION */ if ( (beam_ptr = add_beam_list( frac_ptr, file_list_ptr->image.beam_geometry.beam_number, file_list_ptr->image.beam_geometry.description, file_list_ptr->image.beam_geometry.number_of_treatments, file_list_ptr->image.beam_geometry.rx_dose_per_tx, file_list_ptr->image.beam_geometry.beam_energy, file_list_ptr->image.beam_geometry.modality, file_list_ptr->image.beam_geometry.wedge_angle )) == NULL ) fprintf( stderr, "\nError adding beam to list \n" ); frac_ptr->num_beams++; sprintf( file_type, "BEAM (%d - %s)", file_list_ptr->image.beam_geometry.beam_number, file_list_ptr->image.beam_geometry.description ); break; case eDIGITALFILM: num_films++; /* ADD THE BEAM TO THE INFORMATION */ if ( (beam_ptr = locate_in_beam_list( &data_struct, file_list_ptr->image.film.beam_number )) == NULL ) { fprintf( stdout, "\nError locating beam #%d in list for films\n", file_list_ptr->image.film.beam_number ); break; } /* INCREMENT NUMBER OF APPROPRIATE IMAGES */ if (file_list_ptr->image.film.type == eDRR ) beam_ptr->num_drrs++; else beam_ptr->num_films++; sprintf( file_type, "DIGITAL FILM (%d)", file_list_ptr->image.film.beam_number ); break; case eDOSEDIST: num_doses++; /* INCLUDE IN FRACTION GROUP LIST for tele plans */ if ( data_struct.plan_type != 1 ) break; if ( (frac_ptr = add_frac_group( &data_struct, file_list_ptr->image.dose.fraction_group_id )) == NULL ) { fprintf( stderr, "\nError adding a fraction group\n" ); exit( -1 ); } frac_ptr->num_doses++; if ( file_list_ptr->image.dose.description != NULL ) { if ( (frac_ptr->description = dup_string( file_list_ptr->image.dose.description )) == NULL ) { fprintf( stderr, "\nError: duplicating dose description\n" ); } } sprintf( file_type, "DOSE (%s)", file_list_ptr->image.dose.fraction_group_id ); break; case eDVH: dvh_ptr = data_struct.dvh_names; if ( data_struct.num_dvhs > 0 ) { while( dvh_ptr->next != NULL ) dvh_ptr = (dvh_names_t *)dvh_ptr->next; /* ALLOCATE THE NEXT ENTRY */ if ( (dvh_ptr->next = (struct dvh_names_t *)calloc( (size_t)1, sizeof( dvh_names_t ))) == NULL ) { fprintf( stderr, "\nError allocating dvh_names list\n" ); exit ( -1 ); } dvh_ptr = (dvh_names_t *)dvh_ptr->next; } else { /* ALLOCATE THE HEAD */ if ( (dvh_ptr = data_struct.dvh_names = (dvh_names_t *)calloc( (size_t)1, sizeof( dvh_names_t ))) == NULL ) { fprintf( stderr, "\nError allocating head of dvh_names list\n" ); exit ( -1 ); } } if ( ((dvh_ptr->plan_id = dup_string( file_list_ptr->image.dvh.plan_id_of_origin )) == NULL ) || ((dvh_ptr->struct_id = dup_string( file_list_ptr->image.dvh.struct_name )) == NULL )) fprintf( stderr, "\nError duplicating DVH structure name or plan id\n" ); dvh_ptr->num_bins = file_list_ptr->image.dvh.number_of_pairs; data_struct.num_dvhs++; num_dvh++; sprintf( file_type, "DVH (%s)", file_list_ptr->image.dvh.struct_name ); break; /* catch unhandled cases */ case eIMAGEUNDEF: break; } /* SEE IF THIS FILE EXISTS */ sprintf( filename, tape.format_string, tape.path, tape.prefix, file_list_ptr->image_number, tape.postfix ); if ( stat(filename, &statbuf) != 0 ) { sprintf( aapm_log_string, "File #%04d [%s] is missing", file_list_ptr->image_number, file_type ); /* aapm_status( eAAPM_ERROR, aapm_log_string ); */ sprintf( string, "ERROR: %s", aapm_log_string ); if (missing_files == 0 ) { err_list_ptr = &error_list; } else { err_list_ptr->next = (struct string_list_t *)calloc( (size_t)1, sizeof( string_list_t )); err_list_ptr = (string_list_t *)err_list_ptr->next; } err_list_ptr->entry = dup_string( string ); missing_files++; } /* TRAVERSE THE FILE LINKED LIST */ file_list_ptr = (exch_file_t *)file_list_ptr->next; } /* REPORT RESULTS FOR THE CASE */ fprintf( stdout, "Summary Data for exchange directory:\n %s\n", tape.path ); fprintf( stdout, "\nTape standard: %s\n", tape.tape_standard); fprintf( stdout, "Institution: %s\n", tape.institution); fprintf( stdout, "Date created: %s\n", tape.date_created); fprintf( stdout, "Written by: %s\n", tape.writer); if ( missing_files > 0 ) fprintf( stdout, "\n*** %d FILES ARE MISSING! LIST ATTACHED. ***\n", missing_files ); fprintf( stdout, "\nPatient Name: %s", patcase->patient_name ); fprintf( stdout, "\nCase #: %d", patcase->case_number ); fprintf( stdout, "\nNumber of comment files: %d", num_comment ); fprintf( stdout, "\nNumber of CT files: %d", num_ct ); fprintf( stdout, "\nNumber of MR files: %d", num_mr ); fprintf( stdout, "\nNumber of US files: %d", num_us ); fprintf( stdout, "\nNumber of struct files: %d", num_structs ); fprintf( stdout, "\nNumber of beam files: %d", num_beams ); fprintf( stdout, "\nNumber of seed files: %d", num_seed ); fprintf( stdout, "\nNumber of film files: %d", num_films ); fprintf( stdout, "\nNumber of dose files: %d", num_doses ); fprintf( stdout, "\nNumber of DVH files: %d", num_dvh ); if ( data_struct.num_structs > 0 ) { fprintf( stdout, "\n\nStructure list (%d structures)\n", data_struct.num_structs ); for ( i=0; ifraction_group_id, frac_ptr->description ); /* DUMP TO OUTPUT FILE IF REQUESTED */ if ( output != NULL ) fprintf( output, "FXGID:%s\n", frac_ptr->fraction_group_id ); fprintf( stdout, "\n Total Beams: %d --- Total Dose Distributions: %d", frac_ptr->num_beams, frac_ptr->num_doses ); beam_ptr = frac_ptr->beam_list; while ( beam_ptr != NULL ) { fprintf( stdout, "\n Beam #%2d (%s): %.1f", beam_ptr->beam_number, beam_ptr->description, beam_ptr->energy ); switch( beam_ptr->mode ) { case eXRAY_BEAM: fprintf( stdout, " MV X-ray" ); break; case eELECTRON_BEAM: fprintf( stdout, " MV Electron" ); break; case ePROTON_BEAM: fprintf( stdout, " MV Proton" ); break; case eNEUTRON_BEAM: fprintf( stdout, " MV Neutron" ); break; case eOTHER_BEAM: fprintf( stdout, " MV OTHER" ); break; case eUNDEFMOD: fprintf( stdout, " UNDEFINED" ); break; } /* IF A WEDGE EXISTS, IDENTIFY IT */ if ( beam_ptr->wedge_angle > 0 ) fprintf( stdout, ": %d Degree Wedge", beam_ptr->wedge_angle ); fprintf( stdout, "\n #Tx:%2d, #Drrs:%2d, #Films:%3d, Total cGy:%4d", beam_ptr->num_tx, beam_ptr->num_drrs, beam_ptr->num_films, (int)((float)beam_ptr->num_tx * beam_ptr->dose_per_tx * 100. + 0.5 )); beam_ptr = (beam_info_t *)beam_ptr->next; } /* END OF beam_ptr LOOP */ frac_ptr = (frac_list_t *)frac_ptr->next; } /* END frac_ptr LOOP */ } /* End of tele plan */ else if( data_struct.plan_type == 2 ) /* seed plan */ { seeddata_t *sdptr = &data_struct.plans.seed->seeddata; fprintf(stdout, "\nBrachytherapy seed plan: %s", sdptr->plan_id_of_origin); fprintf(stdout, "\n %d seeds of model: %s", sdptr->nseeds, sdptr->seed_model); fprintf(stdout,"\n were implanted on: %s", sdptr->date); fprintf(stdout,"\n the isotope was: "); if(sdptr->isotope == eI125) fprintf(stdout," I125"); else if(sdptr->isotope == ePD103) fprintf(stdout," PD103"); else fprintf(stdout," Unknown Isotope"); fprintf(stdout, "\n and the seeds had strength: %7.3f", sdptr->strength); if(sdptr->units == eMCI) fprintf(stdout," MCI"); else if(sdptr->units == eCGYCM2PERHR) fprintf(stdout," U"); else fprintf(stdout," in unknown units"); } /* DVH DATA */ if ( data_struct.num_dvhs > 0 ) { fprintf( stdout, "\n\nDVH Data for %d structures/plans:", data_struct.num_dvhs ); dvh_ptr = data_struct.dvh_names; while ( dvh_ptr != NULL ) { fprintf( stdout, "\n Struct: %s (Bins: %d)\n Plan ID: %s", dvh_ptr->struct_id, dvh_ptr->num_bins, dvh_ptr->plan_id ); if ( output != NULL ) fprintf( output, "DVHP/S:%s:%s\n", dvh_ptr->plan_id, dvh_ptr->struct_id ); dvh_ptr = (dvh_names_t *)dvh_ptr->next; } /* END OF DVH LOOP */ } /* Output a newline (some outputs don't) */ fprintf( stdout, "\n" ); /* DUMP OUT THE ERROR INFORMATION FOR MISSING FILES */ if ( missing_files > 0 ) { fprintf( stdout, "\n\nMISSING FILE LIST FOLLOWS:\n\n" ); err_list_ptr = &error_list; for ( i=0; ientry ); err_list_ptr = (string_list_t *)err_list_ptr->next; } } /* CLOSE THE OUTPUT FILE, IF NECESSARY */ if ( output != NULL ) fclose( output ); exit( 0 ); } /************************** End of main() *****************************/ /* */ /***************************************************************************** read_tape_directory() **************************************************************************** Functional Description: Reads in the block data of a tape exchange directory file and parses it into the individual file directory entries; Returns FAILURE if any error occurs, or SUCCESS if completed without error. ***************************************************************************/ int read_tape_directory ( tapedir_t *tape, /* TAPE DIRECTORY STRUCTURE */ char *filename /* TAPE DIRECTORY DISK FILE NAME */ ) { struct stat statbuf; /* USED TO STAT THE DIRECTORY FILE */ FILE *fp; /* FILE POINTER FOR DIRECTORY FILE */ int done_flag; /* FLAG TO SIGNAL END OF DIRECTORY REACHED */ size_t read_size; /* SIZE OF FREAD DATA READ IN */ int retval; /* RETURN VALUE */ /* ENSURE THE DIRECTORY FILE EXISTS, IS THE CORRECT SIZE OPEN IT */ if ( check_open( &fp, filename, tape->block_size, &(tape->num_blocks), &(tape->data_size) ) != SUCCESS ) return( FAILURE ); /* STRIP OFF EXTRANEOUS IDENT STUFF */ *strrchr( RCSname, (int)',' ) = '\0'; *(strrchr( RCSRev, (int)'$' )-1) = '\0'; *(strrchr( RCSDate, (int)'$' )-1) = '\0'; /* REPORT THE PROGRAM AND VERSION BEING USED */ fprintf( stdout, "\nProgram: %s - Version: %s - Date: %s", strchr( RCSname, (int)':' )+2, strchr( RCSRev, (int)':' )+2, strchr( RCSDate, (int)':' )+2 ); /* GET DATE ON THE FILE */ stat(filename, &statbuf); fprintf( stdout, "\nFile system timestamp of directory file: %s\n", ctime( &statbuf.st_mtime ) ); /* ALLOCATE THE DATA BUFFER FOR THE FILE */ if ( (tape->block_data = (char *)malloc( (size_t)tape->data_size )) == NULL ) { fprintf( stderr, "\nError allocating memory for file set block data" ); fprintf( stderr, "\nNeeded %d bytes\n", tape->num_blocks ); fclose( fp ); return( FAILURE ); } /* READ ALL BLOCKS IN */ if ( (read_size = fread( (void *)tape->block_data, (size_t)1, (size_t)tape->data_size, fp )) != tape->data_size ) { fprintf( stderr, "\nError reading directory file: %s", filename ); fprintf( stderr, "\nRead %d bytes of %d of data\n", read_size, tape->data_size ); fclose( fp ); return( FAILURE ); } /* CLOSE THE FILE */ fclose( fp ); /* WALK THROUGH THE DIRECTORY BLOCKS AND BUILD THE DATA STRUCTURES FOR THE DIRECTORY */ done_flag = 0; retval = SUCCESS; /* ASSUME ALL IS WELL */ while( done_flag == 0 ) { if ( next_entry( tape, &done_flag ) != SUCCESS ) { fprintf( stderr, "\nError occurred processing directory entries\n" ); retval = FAILURE; } } /* ALL IS WELL */ return( retval ); } /********************* End of read_tape_directory() ***********************/ /* */ /***************************************************************************** next_entry() **************************************************************************** Functional Description: Parses all directory entries up to, but not including the next image number entry. Returns FAILURE if any error occurs or SUCCESS if all is well. ***************************************************************************/ int next_entry ( tapedir_t *tape, /* TAPE DIRECTORY DATA */ int *done /* FLAG TO SIGNAL END OF DIRECTORY 1 = YES */ ) { int key; /* CURRENT ENTRY'S KEY VALUE */ int value; /* CURRENT ENTRY'S VALUE */ char temp_buf[MAX_LINE_LENGTH]; /* TEMPORARY STRING HOLDER */ char *temp_buf2; /* TEMP STRING POINTER */ int image_number; /* IMAGE NUMBER OF DIRECTORY BEING PROCESSED */ int case_number; /* COPY OF CASE NUMBER */ case_t *patcase; /* CASE POINTER */ exch_file_t *file; /* POINTER TO CURRENT FILE ENTRY */ int not_complete; /* WHILE LOOP TERMINATOR */ int buf_ptr; /* BLOCK DATA BLOCK POINTER - ALLOWS ONE LINE BACK-UP */ int ret_val; /* RETURN VALUE (SUCCESS || FAILURE) */ /* INITIALIZE THE RETURN VALUE TO SUCCESS. IT ONLY GETS RESET ON PROBLEM CHILDREN */ ret_val = SUCCESS; /* WALK THROUGHT THE BLOCK UNTIL THE SECOND IMAGE NUMBER IS FOUND */ not_complete = 0; buf_ptr = tape->offset; while( not_complete == 0 ) { /* UPDATE BLOCK POINTER SINCE LAST IMAGE WAS NOT PATIENT NAME */ tape->offset = buf_ptr; if ( extract_line( tape->block_data, &buf_ptr, tape->data_size, temp_buf, MAX_LINE_LENGTH ) == FAILURE ) { sprintf( aapm_log_string, "Line: %s", temp_buf ); aapm_status( eAAPM_ERROR, aapm_log_string ); *done = 1; return( FAILURE ); } /* IGNORE BLANK LINES */ if ( strlen( temp_buf ) == 0 ) continue; /* PARSE THE ENTRY */ if ( (key = parse_key( temp_buf, key_list, NUM_KEYS, &temp_buf2 )) < 0 ) { fprintf( stderr, "\nError occurred parsing directory entry" ); fprintf( stderr, "\n %s\n", temp_buf ); ret_val = FAILURE; } /* ASSIGN THE APPROPRIATE FIELD */ switch( key ) { case ekTAPESTANDARDNUMBER: tape->tape_standard = temp_buf2; break; case ekINTERCOMPARISONSTANDARDNUMBER: tape->intercomp_standard = temp_buf2; break; case ekINSTITUTION: tape->institution = temp_buf2; break; case ekDATECREATED: tape->date_created = temp_buf2; break; case ekWRITER: tape->writer = temp_buf2; break; case ekIMAGENUMBER: image_number = atoi( temp_buf2 ); free( (void *)temp_buf2 ); /* ALLOCATE THE FILE STRUCTURE */ if ( image_number == 1 ) { if ( (tape->patient_case = (case_t *)calloc( (size_t)1, sizeof( case_t ))) == NULL ) { fprintf( stderr, "\nError occurred malloc'ing case node\n" ); exit( 1 ); } patcase = tape->patient_case; /* START WITH HEAD OF THE LIST IN CASE */ if ( (tape->patient_case->head_file = (exch_file_t *)calloc( (size_t)1, sizeof(exch_file_t ))) == NULL ) { fprintf( stderr, "\nError allocating exchange file node FILE: %d\n", image_number ); ret_val = FAILURE; } file = patcase->head_file; patcase->case_number = -1; } else { /* REINITIALIZE LOCAL POINTERS */ patcase = tape->patient_case; for( file = patcase->head_file; file->next != NULL; file = file->next ); /* ALLOCATE NEXT NODE IN CHAIN */ if ( (file->next = (exch_file_t *)calloc( (size_t)1, sizeof(exch_file_t ))) == NULL ) { fprintf( stderr, "\nError allocating exchange file node FILE: %d\n", image_number); ret_val = FAILURE; } file = file->next; } tape->total_images++; tape->current_image_num = file->image_number = image_number; break; case ekIMAGETYPE: /* PARSE THE KEY VALUE */ value = parse_value( temp_buf2, key_value, NUM_KEY_VALS ); free( (void *)temp_buf2 ); switch( value ) { case evCOMMENT: file->image_flag = eCOMMENT; break; case evCTSCAN: file->image_flag = eCTSCAN; break; case evMRSCAN: file->image_flag = eMRISCAN; break; case evULTRASOUND: file->image_flag = eUSSCAN; break; case evSTRUCTURE: file->image_flag = eSTRUCTURE; break; case evBEAMGEOMETRY: file->image_flag = eBEAMGEOM; break; case evDIGITALFILM: file->image_flag = eDIGITALFILM; break; case evDOSE: file->image_flag = eDOSEDIST; break; case evDOSEVOLUMEHISTOGRAM: file->image_flag = eDVH; break; case evSEEDGEOMETRY: file->image_flag = eSEEDGEOM; break; default: fprintf( stderr, "\nError. Invalid image type(%s)\n", temp_buf ); ret_val = FAILURE; break; } break; case ekCASENUMBER: case_number = atoi( temp_buf2 ); free( (void *)temp_buf2 ); patcase->case_number = case_number; break; case ekPATIENTNAME: if ( patcase->patient_name == NULL ) patcase->patient_name = temp_buf2; else free( temp_buf2 ); tape->offset = buf_ptr; not_complete = 1; break; case ekUNDEFINEDKEY: /* THIS IS ASSUMED TO BE A BLANK LINE AND IS IGNORED */ break; } } /* PULL ALL IMAGE DEPENDENT DATA OUT OF DIRECTORY */ switch( file->image_flag ) { case eCOMMENT: tape->total_comment++; if ( parse_comment_entry( tape, &(file->image.comment), done ) != SUCCESS ) { fprintf( stderr, "\nError occurred in parsing comment directory entries FILE: %d\n", image_number ); ret_val = FAILURE; } break; case eCTSCAN: tape->total_ctscan++; if ( parse_ct_entry( tape, &(file->image.ctscan), done ) != SUCCESS ) { fprintf( stderr, "\nError occurred in parsing CT directory entries FILE: %d\n", image_number ); ret_val = FAILURE; } break; case eMRISCAN: tape->total_mrscan++; if ( parse_mrus_entry( tape, &(file->image.mrusscan), done ) != SUCCESS ) { fprintf( stderr, "\nError occurred in parsing MR directory entry FILE: %d\n", image_number ); ret_val = FAILURE; } break; case eUSSCAN: tape->total_usscan++; if ( parse_mrus_entry( tape, &(file->image.mrusscan), done ) != SUCCESS ) { fprintf( stderr, "\nError occurred in parsing US directory entry FILE: %d\n", image_number ); ret_val = FAILURE; } break; case eSTRUCTURE: tape->total_structure++; if ( parse_anat_entry( tape, &(file->image.structure), done ) != SUCCESS ) { fprintf( stderr, "\nError occurred in parsing struct directory entries FILE: %d\n", image_number ); ret_val = FAILURE; } break; case eBEAMGEOM: tape->total_beam_geometry++; if ( parse_beam_entry( tape, &(file->image.beam_geometry), done ) != SUCCESS ) { fprintf( stderr, "\nError occurred in parsing beam directory entries FILE: %d\n", image_number ); ret_val = FAILURE; } break; case eDIGITALFILM: tape->total_film++; if ( parse_film_entry( tape, &(file->image.film), done ) != SUCCESS ) { fprintf( stderr, "\nError occurred in parsing film directory entries FILE: %d\n", image_number ); ret_val = FAILURE; } break; case eDOSEDIST: tape->total_dose++; if ( parse_dose_entry( tape, &(file->image.dose), done ) != SUCCESS ) { fprintf( stderr, "\nError occurred in parsing dose directory entries FILE: %d\n", image_number ); ret_val = FAILURE; } break; case eDVH: tape->total_dvh++; if ( parse_dvh_entry( tape, &(file->image.dvh), done ) != SUCCESS ) { fprintf( stderr, "\nError occurred in parsing dvh directory entries FILE: %d\n", image_number ); ret_val = FAILURE; } break; case eSEEDGEOM: tape->total_seed_geometry++; if ( parse_seed_entry( tape, &(file->image.seeddata), done ) != SUCCESS ) { fprintf( stderr, "\nError occurred in parsing seed directory entries FILE: %d\n", image_number ); ret_val = FAILURE; } break; default: fprintf( stderr, "\nInvalid image type found. FILE: %d\n", image_number ); ret_val = FAILURE; } /* ALL IS WELL */ return( ret_val ); } /************************** End of next_entry *****************************/ /* */ /***************************************************************************** file_blocks() **************************************************************************** Functional Description: Checks to see if the file size is an integral multiple of the tape block size. Returns FAILURE if size is not integral multiple of tape block size and SUCCESS if it is. ***************************************************************************/ int file_blocks ( char *filename, /* FILENAME TO CHECK */ int block_size, /* BLOCK SIZE */ int *num_blocks, /* NUMBER OF BLOCKS CONTAINED */ int *file_size /* SIZE OF FILE */ ) { struct stat statbuf; /* ENSURE THE FILE EXISTS */ if ( stat(filename, &statbuf) == -1 ) { fprintf( stderr, "\nFile: %s - does not exist\n", filename ); return( FAILURE ); } /* DETERMINE THE SIZE OF THE DIRECTORY FILE */ *file_size = (int)statbuf.st_size; /* ENSURE THAT THE FILE IS AN INTEGRAL NUMBER OF BLOCKS LONG */ if ( block_size == 0 ) *num_blocks = 1; else { if ( (*file_size % block_size) != 0 ) { fprintf( stderr, "\nError in file size" ); fprintf( stderr, "\nFile: %s", filename ); fprintf( stderr, "\nLength = %d, Block Size = %d\n", *file_size, block_size ); return( FAILURE ); } /* SET THE NUMBER OF BLOCKS */ *num_blocks = *file_size / block_size; } return( SUCCESS ); } /************************** End of file_blocks() ***************************/ /* */ /***************************************************************************** check_open() **************************************************************************** Functional Description: Checks the length of an exchange file and opens it, returning the pointer to the stream. Fails if size is not integral number of buffers or if open fails. Returns SUCCESS or FAILURE on an error. ***************************************************************************/ int check_open ( FILE **fp, /* FILE STREAM POINTER */ char *filename, /* FILE NAME */ int block_size, /* SIZE OF BUFFER IN BYTES */ int *num_blocks, /* NUMBER OF BLOCKS IN FILE */ int *file_size /* SIZE OF FILE IN BYTES */ ) { /* CHECK NUMBER OF BLOCKS IN FILE */ if ( file_blocks( filename, block_size, num_blocks, file_size ) != SUCCESS ) /* FOR NOW ONLY TELL USER THERE IS A PROBLEM */ fprintf( stderr, "\nError in file block count\n" ); /* OPEN THE FILE */ if ( (*fp = fopen( filename, "r" )) == NULL ) { fprintf( stderr, "\nError opening file: %s\n", filename ); return( FAILURE ); } return( SUCCESS ); } /************************* End of check_open() *************************/ /* */ /***************************************************************************** add_frac_group() **************************************************************************** Functional Description: Adds fraction group id to existing list or creates head of list. Returns NULL on failure or address of fraction list entry. ***************************************************************************/ static frac_list_t *add_frac_group ( datalist_t *data_struct, /* DIRECTORY INFO STRUCTURE */ char *group_id /* FRACTION GROUP ID */ ) { frac_list_t *frac_ptr; /* CURRENT LIST ENTRY */ frac_list_t *prev_frac_ptr; /* PREVIOUS LIST ENTRY */ /* FIND FRACTION GROUP ID TO ADD TO */ frac_ptr = data_struct->plans.tele; prev_frac_ptr = NULL; while( frac_ptr != NULL && strcmp( frac_ptr->fraction_group_id, group_id ) != 0 ) { prev_frac_ptr = frac_ptr; frac_ptr = (frac_list_t *)frac_ptr->next; } if ( frac_ptr == NULL ) { /* NO EXISTING FRACTION ENTRY. ADD ONE */ if ( prev_frac_ptr == NULL ) { /* ALLOCATE HEAD OF LIST */ if ( (data_struct->plans.tele = frac_ptr = (frac_list_t *)calloc( (size_t)1, sizeof( frac_list_t ))) == NULL ) { fprintf( stderr, "\nError allocating head of fraction list\n" ); return( NULL ); } } else { /* ADD A NEW FRACTION NODE TO EXISTING LIST */ if ( (frac_ptr = prev_frac_ptr->next = (struct frac_list_t *)calloc( (size_t)1, sizeof( frac_list_t ))) == NULL ) { fprintf( stderr, "\nError allocating link of fraction list\n" ); return( NULL ); } } /* PUT THE GROUP ID INTO THE LIST ENTRY */ if ( (frac_ptr->fraction_group_id = dup_string( group_id )) == NULL ) { fprintf( stderr, "\nError duplicating fraction group id string\n" ); return( NULL ); } /* INCREMENT THE PLAN COUNT */ data_struct->num_plans++; } /* ALL IS WELL */ return( frac_ptr ); } /************************* End of add_frac_group() *************************/ /* */ /***************************************************************************** add_beam_list() **************************************************************************** Functional Description: Adds beam information to fraction list structure. Returns SUCCESS or FAILURE. ***************************************************************************/ static beam_info_t *add_beam_list ( frac_list_t *frac_ptr, /* FRACTION INFORMATION POINTER */ int beam_number, /* BEAM NUMBER TO ADD */ char *description, /* BEAM DESCRIPTION */ int num_tx, /* # OF TREATMENTS */ float dose_per_tx, /* DOSE (GY) PER TX */ float energy, /* BEAM ENERGY IN MV/MEV */ beam_modality_type mode, /* BEAM MODALITY */ int wedge_angle /* WEDGE ANGLE */ ) { beam_info_t *beam_ptr; /* CURRENT LIST ENTRY */ beam_info_t *prev_ptr; /* PREVIOUS LIST ENTRY */ /* ADD TO LIST (ENSURE NO DUPLICATION OF BEAM NUMBER) */ beam_ptr = frac_ptr->beam_list; prev_ptr = NULL; while( beam_ptr != NULL && beam_ptr->beam_number != beam_number ) { prev_ptr = beam_ptr; beam_ptr = (beam_info_t *)beam_ptr->next; } /* IF beam_ptr != NULL THEN A DUPLICATE BEAM NUMBER HAS BEEN FOUND */ if ( beam_ptr != NULL ) { fprintf( stderr, "\nDuplicate beam number %d encountered\n", beam_number ); return( NULL ); } /* NO EXISTING BEAM ENTRY. ADD ONE */ if ( prev_ptr == NULL ) { /* ALLOCATE HEAD OF LIST */ if ( (frac_ptr->beam_list = beam_ptr = (beam_info_t *)calloc( (size_t)1, sizeof( beam_info_t ))) == NULL ) { fprintf( stderr, "\nError allocating head of beam list\n" ); return( NULL ); } } else { /* ADD A NEW FRACTION NODE TO EXISTING LIST */ if ( (prev_ptr->next = (struct beam_info_t *)calloc( (size_t)1, sizeof( beam_info_t ))) == NULL ) { fprintf( stderr, "\nError allocating link of beam info list\n" ); return( NULL ); } beam_ptr = (beam_info_t *)prev_ptr->next; } /* PUT THE BEAM DESCRIPTION INTO INFO STRUCTURE */ if ( (beam_ptr->description = dup_string( description )) == NULL ) { fprintf( stderr, "\nError duplicating beam description string\n" ); return( NULL ); } beam_ptr->num_drrs = beam_ptr->num_films = 0; beam_ptr->beam_number = beam_number; beam_ptr->num_tx = num_tx; beam_ptr->dose_per_tx = dose_per_tx; beam_ptr->energy = energy; beam_ptr->mode = mode; beam_ptr->wedge_angle = wedge_angle; /* ALL IS WELL */ return( beam_ptr ); } /************************* End of add_beam_list() *************************/ /* */ /***************************************************************************** locate_in_beam_list() **************************************************************************** Functional Description: Adds beam information to fraction list structure. Returns SUCCESS or FAILURE. ***************************************************************************/ static beam_info_t *locate_in_beam_list ( datalist_t *data_struct, /* DIRECTORY INFO STRUCTURE */ int beam_number /* BEAM NUMBER TO ADD */ ) { frac_list_t *frac_ptr; /* FRACTION POINTER FOR LINKED LIST */ beam_info_t *beam_ptr; /* CURRENT LIST ENTRY */ int done; /* FLAG FOR DONE WITH LIST */ /* FIND THE MATCHING BEAM NUMBER IN THE CURRENT FRACTION GROUPS */ done = 0; frac_ptr = data_struct->plans.tele; beam_ptr = NULL; while ( frac_ptr != NULL && done == 0 ) { /* CHECK FOR APPROPRIATE BEAM NUMBER IN THIS FRACTION */ beam_ptr = frac_ptr->beam_list; while ( beam_ptr != NULL && done == 0 ) { /* WALK THIS LIST LOOKING FOR A MATCH */ if ( beam_ptr->beam_number == beam_number ) { done = 1; break; } else beam_ptr = (beam_info_t *)beam_ptr->next; } /* WALK LIST */ frac_ptr = (frac_list_t *)frac_ptr->next; } /* RETURN LOCATED POINTER */ return( beam_ptr ); } /******************** End of locate_in_beam_list() ********************/ /******************** End of ident_x_tape.c ***************************/