1 /******************************************************************************
5 * $Date: 2007/03/26 03:20:31 $
9 * Revision 2.2 2007/03/26 03:20:31 hachti
10 * *** empty log message ***
12 * Revision 2.1 2007-03-26 01:15:21 hachti
13 * *** empty log message ***
15 * Revision 2.0 2007-03-26 01:00:40 hachti
16 * *** empty log message ***
19 ******************************************************************************/
21 #include <sys/types.h>
31 #include "tape_block.hh"
32 #include "data_block_0.hh"
37 #define BUILD_STAMP ""
44 #define ID_STRING "\n ldc2 - The X16 object tape analyser\n\
45 (C) 2007 Philipp Hachtmann\n\n\
46 Version %s, built %s\n %s\n\n"
48 /******************************************************************************/
50 static FILE * stdwarn
; //! Suppressable warning output file pointer.
51 static vector
<tape_block
*> tape
; //! The whole tape contents.
52 static vector
<vector
<tape_block
*> > objects
; //! Tape content in objects.
54 static int errors
= 0; //! Global error counter.
55 static int warnings
= 0; //! Global warning counter.
56 static int errcode
= 0; //! Error code for error exit routine.
59 /******************************************************************************/
61 *\brief Error exit routine.
63 * This routine tests the global error counter and terminates the program
68 fprintf(stderr
,"Failed. (%i)\n",errcode
);
74 /******************************************************************************/
76 *\brief Read in Tape data and do some checks and messages.
78 * This routine reads in the tape data.
79 * During reading in, checksums are checked and
80 * /da001/ information is generated. No object integrity test.
81 * Tape block object pointers are put into the global vector
86 tape_block
* block
=0; //! Pointer to current block.
87 bool read_ahead
=true; //! Continue scanning for blocks.
88 int read_pointer
=0; //! Read position in input.
89 int block_start
=0; //! Start of block position in input.
90 int block_end
=0; //! End of block position in input.
91 int blocks_read
=0; //! Number of blocks read in.
93 bool spaced
=false; //! Help flag for spaced messages.
95 string message
; //! A warning or help message.
100 bool err_checksum
=false; //! Checksum error flag.
101 bool err_integrity
=false; //! Integrity error flag.
103 bool warning
=false; //! Warning flag.
104 bool error
=false; //! Error flag.
106 // Try to generate block
108 block
=tape_block::gen_from_fd(in_fd
);
111 catch(tape_block::eof_legal_exception
&e
){
112 read_pointer
+=e
.get_consumed();
113 break; // Immediately leave read loop.
116 catch(tape_block::io_error_exception
){
118 fprintf(stderr
,"Error: Could not read from \"%s\"!\n",
121 fprintf(stderr
,"Error: Could not read from stdin!\n");
125 break; // Immediately leave read loop.
128 catch(tape_block::eof_illegal_exception
&e
){
132 if (cfg_ignore_block_errors
){
133 message
="Warning: Block integrity check failed!\n";
136 message
="Error: Block integrity check failed!\n";
142 catch(tape_block::checksum_error_exception
&e
){
145 if (cfg_ignore_checksum_errors
){
146 message
="Warning: Block checksum wrong!\n";
149 message
="Error: Block checksum wrong!\n";
156 // Now let's check for block type
157 if ((!error
)&&(!warning
)&&!block
->has_known_type()){
158 if (cfg_ignore_unknown_block_errors
){
159 message
="Warning: Unknown Block type!";
162 message
="Error: Unknown Block type!";
171 tape
.insert(tape
.end(),block
);
172 block_start
=read_pointer
+block
->get_discarded_bytes();
173 block_end
=block_start
+block
->get_raw_size()-1;
174 read_pointer
=block_end
+1;
177 if (error
) fp
=stderr
;
179 if (cfg_verbose
||error
||warning
){
180 if (!spaced
) fprintf(fp
,"\n");
182 fprintf(fp
,"Block No.%03i: Start:0x%04x End:0x%04x Size:0x%02x\n",
186 block
->get_raw_size());
189 if (error
) fprintf(stderr
,message
.c_str());
190 if (warning
) fprintf(stdwarn
,message
.c_str());
193 dump_vector(block
->get_description());
195 if(cfg_list_contents
){
196 FILE * tmp_fp
=fdopen(out_fd
,"w");
197 dump_vector_fp(block
->get_description(),tmp_fp
);
198 if (!error
&&!warning
) spaced
=false;
202 if (error
||warning
||cfg_verbose
){
207 if (warning
) warnings
++;
211 fprintf(stderr
,"Reading finished.\n");
212 fprintf(stderr
,"Bytes read:%i, Blocks read:%i\n",read_pointer
,blocks_read
);
217 /******************************************************************************/
219 *\brief Do integrity test and object or block dumps.
222 if (cfg_verbose
) fprintf(stdwarn
,"\nProcessing Data.\n");
224 bool in_object
=false;
226 char filename_numbered
[100];
228 int unknown_count
=-1;
229 int fd
=-1, fd_numbered
=-1;
233 for (unsigned int i
=0; i
<tape
.size();i
++){
234 tape_block
* block
=tape
[i
];
236 if (block
->get_type()==tape_block::TBT_EOT
){
239 if (cfg_ignore_object_integrity_errors
){
240 fprintf(stdwarn
,"Warning: Object integrity error!\
241 (Object no %i, Block %i unexpected)\n",obj_no
,i
);
244 fprintf(stderr
,"Error: Object integrity error!\
245 (Object no %i, Block %i unexpected)\n",obj_no
,i
);
252 if (!in_object
){ // object begin
260 vector
<string
>names
=block
->get_exported_symbols();
261 for (unsigned int a
=0; a
<names
.size();a
++){
264 objname
=objname
.substr(0,objname
.find_last_not_of(" ")+1);
270 if (block
->get_type()==tape_block::TBT_EOT
){
274 // Open file for split objects
275 if (cfg_split_objects
&& (block
->get_type()!=tape_block::TBT_EOT
)){
276 if (objname
=="UNKNOWN")snprintf(filename
,99,"UNKNOWN%02i.obj",
278 else snprintf(filename
,99,"%s.obj",objname
.c_str());
279 if (fd
>-1) close (fd
);
280 if (cfg_verbose
) fprintf(stdwarn
,"Writing file: %s\n",filename
);
281 fd
=open(filename
,O_WRONLY
|O_CREAT
|O_TRUNC
,0666);
283 fprintf(stderr
,"Error: could not open file \"%s\" for writing!\n",
291 // Open file for split objects numbered
292 snprintf(filename_numbered
,99,"%03i0-%s.obj",obj_no
,objname
.c_str());
293 if (cfg_split_objects_numbered
){
295 if (cfg_verbose
) fprintf(stdwarn
,"Writing file: %s\n",filename_numbered
);
296 fd_numbered
=open(filename_numbered
,O_WRONLY
|O_CREAT
|O_TRUNC
,0666);
298 fprintf(stderr
,"Error: could not open file \"%s\" for writing!\n",
309 if (cfg_split_objects
){
311 if (block
->get_type()!=tape_block::TBT_EOT
) // Don't want EOT here
312 block
->dump_to_fd(fd
);
314 catch (tape_block::io_error_exception e
){
315 fprintf(stderr
,"Error: could write to file \"%s\"!\n",
321 } // if (cfg_split_objects)
324 if (cfg_split_objects_numbered
){
326 block
->dump_to_fd(fd_numbered
);
328 catch (tape_block::io_error_exception e
){
329 fprintf(stderr
,"Error: could write to file \"%s\"!\n",
335 } // if (cfg_split_objects_numbered)
337 // Output individual block file if desired
338 if (cfg_split_blocks
){
340 snprintf(fname
,99,"%03i0-%s-%03i.block",obj_no
,objname
.c_str(),
342 if (cfg_verbose
) fprintf(stdwarn
,"Writing file: %s\n",fname
);
343 int fd_block
=open(fname
,O_WRONLY
|O_TRUNC
|O_CREAT
,0666);
345 fprintf(stderr
,"Error: could not open file \"%s\" for writing!\n",
354 block
->dump_to_fd(fd_block
);
356 catch (tape_block::io_error_exception e
){
357 fprintf(stderr
,"Error: could write to file \"%s\"!\n",
368 if (block
->is_endblock()||(block
->get_type()==tape_block::TBT_EOT
)) {
376 if (cfg_ignore_object_integrity_errors
){
377 fprintf(stdwarn
,"Warning: Object integrity error! Last object incomplete!\n");
380 fprintf(stdwarn
,"Error: Object integrity error! Last Object incomplete!\n");
383 if (fd
!=-1) close(fd
);
384 if (fd_numbered
!=-1) close(fd_numbered
);
390 /******************************************************************************/
392 *\brief Everything that has to do with symbol listing.
394 void process_symbols(){
395 vector
<string
>exported
;
396 vector
<string
>called
;
397 vector
<string
>unsatisfied
;
399 if (cfg_verbose
) fprintf(stdwarn
,"\nProcessing Symbols.\n");
401 for (unsigned int i
=0; i
<tape
.size();i
++){
402 merge_vector_unique(exported
,tape
[i
]->get_exported_symbols());
403 merge_vector_unique(called
,tape
[i
]->get_called_symbols());
406 for (unsigned int icalled
=0;icalled
<called
.size();icalled
++){
408 for (unsigned int iexported
=0;iexported
<exported
.size();iexported
++){
409 if (exported
[iexported
].compare(called
[icalled
])==0){
416 for (unsigned int i
=0;i
<unsatisfied
.size();i
++){
417 if (unsatisfied
[i
].compare(called
[icalled
])==0){
422 if (!present
) unsatisfied
.insert(unsatisfied
.end(),called
[icalled
]);
426 FILE * outp
=fdopen(out_fd
,"w");
428 if (cfg_output_called
){
429 dump_vector_fp(called
,outp
);
432 if (cfg_output_exported
){
433 dump_vector_fp(exported
,outp
);
436 if (cfg_output_unsatisfied
){
437 dump_vector_fp(unsatisfied
,outp
);
440 } // process_symbols()
442 /******************************************************************************/
444 *\brief The main routine.
447 int main(int argc
, char ** args
){
449 // Do all the configuration stuff
450 do_config(argc
,args
);
452 // Output a version message if desired
454 fprintf(stderr
, ID_STRING
, VERSION
, BUILD_DATE
, BUILD_STAMP
);
458 // Assign warning output according to configuration
459 if (cfg_quiet
) stdwarn
=fopen("/dev/null","w");
462 read_tape(); // Process input to completion.
472 fprintf(stdwarn
,"Warnings:%i\n",warnings
);
475 if (cfg_verbose
) fprintf(stdwarn
,"\nSuccess.\n");
479 * All over this program, no memory is freed. This is not necessary because
480 * everything is allocated once and that's it.
481 * The classes support proper freeing of their internal buffers.
486 /******************************************************************************/