1 /******************************************************************************
5 * $Date: 2007/05/30 02:51:16 $
9 * Revision 2.3 2007/05/30 02:51:16 hachti
10 * Changed everything towards LDC2 use.
11 * Worked on the buildlib.sh.
12 * Centralized buildlib.sh to a new lib/common directory.
14 * Revision 2.2 2007-03-26 03:20:31 hachti
15 * *** empty log message ***
17 * Revision 2.1 2007-03-26 01:15:21 hachti
18 * *** empty log message ***
20 * Revision 2.0 2007-03-26 01:00:40 hachti
21 * *** empty log message ***
24 ******************************************************************************/
26 #include <sys/types.h>
36 #include "tape_block.hh"
37 #include "data_block_0.hh"
42 #define BUILD_STAMP ""
49 #define ID_STRING "\n ldc2 - The X16 object tape analyser\n\
50 (C) 2007 Philipp Hachtmann\n\n\
51 Version %s, built %s\n %s\n\n"
53 /******************************************************************************/
55 static FILE * stdwarn
; //! Suppressable warning output file pointer.
56 static vector
<tape_block
*> tape
; //! The whole tape contents.
57 static vector
<vector
<tape_block
*> > objects
; //! Tape content in objects.
59 static int errors
= 0; //! Global error counter.
60 static int warnings
= 0; //! Global warning counter.
61 static int errcode
= 0; //! Error code for error exit routine.
64 /******************************************************************************/
66 *\brief Error exit routine.
68 * This routine tests the global error counter and terminates the program
73 fprintf(stderr
,"Failed. (%i)\n",errcode
);
79 /******************************************************************************/
81 *\brief Read in Tape data and do some checks and messages.
83 * This routine reads in the tape data.
84 * During reading in, checksums are checked and
85 * /da001/ information is generated. No object integrity test.
86 * Tape block object pointers are put into the global vector
91 tape_block
* block
=0; //! Pointer to current block.
92 bool read_ahead
=true; //! Continue scanning for blocks.
93 int read_pointer
=0; //! Read position in input.
94 int block_start
=0; //! Start of block position in input.
95 int block_end
=0; //! End of block position in input.
96 int blocks_read
=0; //! Number of blocks read in.
98 bool spaced
=false; //! Help flag for spaced messages.
100 string message
; //! A warning or help message.
105 bool err_checksum
=false; //! Checksum error flag.
106 bool err_integrity
=false; //! Integrity error flag.
108 bool warning
=false; //! Warning flag.
109 bool error
=false; //! Error flag.
111 // Try to generate block
113 block
=tape_block::gen_from_fd(in_fd
);
116 catch(tape_block::eof_legal_exception
&e
){
117 read_pointer
+=e
.get_consumed();
118 break; // Immediately leave read loop.
121 catch(tape_block::io_error_exception
){
123 fprintf(stderr
,"Error: Could not read from \"%s\"!\n",
126 fprintf(stderr
,"Error: Could not read from stdin!\n");
130 break; // Immediately leave read loop.
133 catch(tape_block::eof_illegal_exception
&e
){
137 if (cfg_ignore_block_errors
){
138 message
="Warning: Block integrity check failed!\n";
141 message
="Error: Block integrity check failed!\n";
147 catch(tape_block::checksum_error_exception
&e
){
150 if (cfg_ignore_checksum_errors
){
151 message
="Warning: Block checksum wrong!\n";
154 message
="Error: Block checksum wrong!\n";
161 // Now let's check for block type
162 if ((!error
)&&(!warning
)&&!block
->has_known_type()){
163 if (cfg_ignore_unknown_block_errors
){
164 message
="Warning: Unknown Block type!";
167 message
="Error: Unknown Block type!";
176 tape
.insert(tape
.end(),block
);
177 block_start
=read_pointer
+block
->get_discarded_bytes();
178 block_end
=block_start
+block
->get_raw_size()-1;
179 read_pointer
=block_end
+1;
182 if (error
) fp
=stderr
;
184 if (cfg_verbose
||error
||warning
){
185 if (!spaced
) fprintf(fp
,"\n");
187 fprintf(fp
,"Block No.%03i: Start:0x%04x End:0x%04x Size:0x%02x\n",
191 block
->get_raw_size());
194 if (error
) fprintf(stderr
,message
.c_str());
195 if (warning
) fprintf(stdwarn
,message
.c_str());
198 dump_vector(block
->get_description());
200 if(cfg_list_contents
){
201 FILE * tmp_fp
=fdopen(out_fd
,"w");
202 dump_vector_fp(block
->get_description(),tmp_fp
);
203 if (!error
&&!warning
) spaced
=false;
207 if (error
||warning
||cfg_verbose
){
212 if (warning
) warnings
++;
216 fprintf(stderr
,"Reading finished.\n");
217 fprintf(stderr
,"Bytes read:%i, Blocks read:%i\n",read_pointer
,blocks_read
);
222 /******************************************************************************/
224 *\brief Do integrity test and object or block dumps.
227 if (cfg_verbose
) fprintf(stdwarn
,"\nProcessing Data.\n");
229 bool in_object
=false;
231 char filename_numbered
[100];
233 int unknown_count
=-1;
234 int fd
=-1, fd_numbered
=-1;
238 for (unsigned int i
=0; i
<tape
.size();i
++){
239 tape_block
* block
=tape
[i
];
241 if (block
->get_type()==tape_block::TBT_EOT
){
244 if (cfg_ignore_object_integrity_errors
){
245 fprintf(stdwarn
,"Warning: Object integrity error!\
246 (Object no %i, Block %i unexpected)\n",obj_no
,i
);
249 fprintf(stderr
,"Error: Object integrity error!\
250 (Object no %i, Block %i unexpected)\n",obj_no
,i
);
257 if (!in_object
){ // object begin
265 vector
<string
>names
=block
->get_exported_symbols();
266 for (unsigned int a
=0; a
<names
.size();a
++){
269 objname
=objname
.substr(0,objname
.find_last_not_of(" ")+1);
275 if (block
->get_type()==tape_block::TBT_EOT
){
279 // Open file for split objects
280 if (cfg_split_objects
&& (block
->get_type()!=tape_block::TBT_EOT
)){
281 if (objname
=="UNKNOWN")snprintf(filename
,99,"UNKNOWN%02i",
283 else snprintf(filename
,99,"%s",objname
.c_str());
284 if (fd
>-1) close (fd
);
285 if (cfg_verbose
) fprintf(stdwarn
,"Writing file: %s\n",filename
);
286 fd
=open(filename
,O_WRONLY
|O_CREAT
|O_TRUNC
,0666);
288 fprintf(stderr
,"Error: could not open file \"%s\" for writing!\n",
296 // Open file for split objects numbered
297 snprintf(filename_numbered
,99,"%03i0-%s",obj_no
,objname
.c_str());
298 if (cfg_split_objects_numbered
){
300 if (cfg_verbose
) fprintf(stdwarn
,"Writing file: %s\n",filename_numbered
);
301 fd_numbered
=open(filename_numbered
,O_WRONLY
|O_CREAT
|O_TRUNC
,0666);
303 fprintf(stderr
,"Error: could not open file \"%s\" for writing!\n",
314 if (cfg_split_objects
){
316 if (block
->get_type()!=tape_block::TBT_EOT
) // Don't want EOT here
317 block
->dump_to_fd(fd
);
319 catch (tape_block::io_error_exception e
){
320 fprintf(stderr
,"Error: could write to file \"%s\"!\n",
326 } // if (cfg_split_objects)
329 if (cfg_split_objects_numbered
){
331 block
->dump_to_fd(fd_numbered
);
333 catch (tape_block::io_error_exception e
){
334 fprintf(stderr
,"Error: could write to file \"%s\"!\n",
340 } // if (cfg_split_objects_numbered)
342 // Output individual block file if desired
343 if (cfg_split_blocks
){
345 snprintf(fname
,99,"%03i0-%s-%03i.block",obj_no
,objname
.c_str(),
347 if (cfg_verbose
) fprintf(stdwarn
,"Writing file: %s\n",fname
);
348 int fd_block
=open(fname
,O_WRONLY
|O_TRUNC
|O_CREAT
,0666);
350 fprintf(stderr
,"Error: could not open file \"%s\" for writing!\n",
359 block
->dump_to_fd(fd_block
);
361 catch (tape_block::io_error_exception e
){
362 fprintf(stderr
,"Error: could write to file \"%s\"!\n",
373 if (block
->is_endblock()||(block
->get_type()==tape_block::TBT_EOT
)) {
381 if (cfg_ignore_object_integrity_errors
){
382 fprintf(stdwarn
,"Warning: Object integrity error! Last object incomplete!\n");
385 fprintf(stdwarn
,"Error: Object integrity error! Last Object incomplete!\n");
388 if (fd
!=-1) close(fd
);
389 if (fd_numbered
!=-1) close(fd_numbered
);
395 /******************************************************************************/
397 *\brief Everything that has to do with symbol listing.
399 void process_symbols(){
400 vector
<string
>exported
;
401 vector
<string
>called
;
402 vector
<string
>unsatisfied
;
404 if (cfg_verbose
) fprintf(stdwarn
,"\nProcessing Symbols.\n");
406 for (unsigned int i
=0; i
<tape
.size();i
++){
407 merge_vector_unique(exported
,tape
[i
]->get_exported_symbols());
408 merge_vector_unique(called
,tape
[i
]->get_called_symbols());
411 for (unsigned int icalled
=0;icalled
<called
.size();icalled
++){
413 for (unsigned int iexported
=0;iexported
<exported
.size();iexported
++){
414 if (exported
[iexported
].compare(called
[icalled
])==0){
421 for (unsigned int i
=0;i
<unsatisfied
.size();i
++){
422 if (unsatisfied
[i
].compare(called
[icalled
])==0){
427 if (!present
) unsatisfied
.insert(unsatisfied
.end(),called
[icalled
]);
431 FILE * outp
=fdopen(out_fd
,"w");
433 if (cfg_output_called
){
434 dump_vector_fp(called
,outp
);
437 if (cfg_output_exported
){
438 dump_vector_fp(exported
,outp
);
441 if (cfg_output_unsatisfied
){
442 dump_vector_fp(unsatisfied
,outp
);
445 } // process_symbols()
447 /******************************************************************************/
449 *\brief The main routine.
452 int main(int argc
, char ** args
){
454 // Do all the configuration stuff
455 do_config(argc
,args
);
457 // Output a version message if desired
459 fprintf(stderr
, ID_STRING
, VERSION
, BUILD_DATE
, BUILD_STAMP
);
463 // Assign warning output according to configuration
464 if (cfg_quiet
) stdwarn
=fopen("/dev/null","w");
467 read_tape(); // Process input to completion.
477 fprintf(stdwarn
,"Warnings:%i\n",warnings
);
480 if (cfg_verbose
) fprintf(stdwarn
,"\nSuccess.\n");
484 * All over this program, no memory is freed. This is not necessary because
485 * everything is allocated once and that's it.
486 * The classes support proper freeing of their internal buffers.
491 /******************************************************************************/