ldc2: Cosmetic fixes and support for compiler orverride
[h316.git] / pc-tools / ldc2 / src / main.cpp
1 /******************************************************************************
2 *
3 * LDC2 source code
4 *
5 * $Date: 2010/01/04 02:10:59 $
6 * $Author: hachti $
7 *
8 * $Log: main.cpp,v $
9 * Revision 2.6 2010/01/04 02:10:59 hachti
10 * *** empty log message ***
11 *
12 * Revision 2.5 2008-10-01 13:30:14 hachti
13 * Added some includes
14 *
15 * Revision 2.4 2008-08-25 21:02:24 hachti
16 * *** empty log message ***
17 *
18 * Revision 2.3 2007-05-30 02:51:16 hachti
19 * Changed everything towards LDC2 use.
20 * Worked on the buildlib.sh.
21 * Centralized buildlib.sh to a new lib/common directory.
22 *
23 * Revision 2.2 2007-03-26 03:20:31 hachti
24 * *** empty log message ***
25 *
26 * Revision 2.1 2007-03-26 01:15:21 hachti
27 * *** empty log message ***
28 *
29 * Revision 2.0 2007-03-26 01:00:40 hachti
30 * *** empty log message ***
31 *
32 *
33 ******************************************************************************/
34
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42
43
44 #include <vector>
45 #include <string>
46
47 #include "config.hh"
48 #include "tool.hh"
49
50 #include "tape_block.hh"
51 #include "data_block_0.hh"
52
53 using namespace std;
54
55 #ifndef BUILD_STAMP
56 #define BUILD_STAMP ""
57 #endif
58
59 #ifndef VERSION
60 #define VERSION "0.0"
61 #endif
62
63 #define ID_STRING "\n ldc2 - The X16 object tape analyser\n\
64 (C) 2007 Philipp Hachtmann\n\n\
65 Version %s, built %s\n %s\n\n"
66
67 /******************************************************************************/
68
69 static FILE * stdwarn; //! Suppressable warning output file pointer.
70 static vector<tape_block*> tape; //! The whole tape contents.
71 static vector<vector<tape_block*> > objects; //! Tape content in objects.
72
73 static int errors = 0; //! Global error counter.
74 static int warnings= 0; //! Global warning counter.
75 static int errcode = 0; //! Error code for error exit routine.
76
77
78 /******************************************************************************/
79 /*!
80 *\brief Error exit routine.
81 *
82 * This routine tests the global error counter and terminates the program
83 * if necessary.
84 */
85 void exit_on_error(){
86 if (errors){
87 fprintf(stderr,"Failed. (%i)\n",errcode);
88 exit(errcode);
89 }
90 }
91
92
93 /******************************************************************************/
94 /*!
95 *\brief Read in Tape data and do some checks and messages.
96 *
97 * This routine reads in the tape data.
98 * During reading in, checksums are checked and
99 * /da001/ information is generated. No object integrity test.
100 * Tape block object pointers are put into the global vector
101 * tape.
102 */
103 void read_tape(){
104
105 tape_block * block=0; //! Pointer to current block.
106 bool read_ahead=true; //! Continue scanning for blocks.
107 int read_pointer=0; //! Read position in input.
108 int block_start=0; //! Start of block position in input.
109 int block_end=0; //! End of block position in input.
110 int blocks_read=0; //! Number of blocks read in.
111
112 bool spaced=false; //! Help flag for spaced messages.
113
114 string message; //! A warning or help message.
115
116
117 while(read_ahead){
118
119 // bool err_checksum=false; //! Checksum error flag.
120 // bool err_integrity=false; //! Integrity error flag.
121
122 bool warning=false; //! Warning flag.
123 bool error=false; //! Error flag.
124
125 // Try to generate block
126 try{
127 block=tape_block::gen_from_fd(in_fd);
128 }
129
130 catch(tape_block::eof_legal_exception &e){
131 read_pointer+=e.get_consumed();
132 break; // Immediately leave read loop.
133 }
134
135 catch(tape_block::io_error_exception){
136 if (in_fd){
137 fprintf(stderr,"Error: Could not read from \"%s\"!\n",
138 cfg_infile.c_str());
139 } else {
140 fprintf(stderr,"Error: Could not read from stdin!\n");
141 }
142 error=true;
143 errcode=2;
144 break; // Immediately leave read loop.
145 }
146
147 catch(tape_block::eof_illegal_exception &e){
148 block=e.get_block();
149 // err_integrity=true;
150 read_ahead=false;
151 if (cfg_ignore_block_errors){
152 message="Warning: Block integrity check failed!\n";
153 warning=true;
154 } else {
155 message="Error: Block integrity check failed!\n";
156 error=true;
157 errcode=3;
158 }
159 }
160
161 catch(tape_block::checksum_error_exception &e){
162 block=e.get_block();
163 // err_checksum=true;
164 if (cfg_ignore_checksum_errors){
165 message="Warning: Block checksum wrong!\n";
166 warning=true;
167 } else {
168 message="Error: Block checksum wrong!\n";
169 error=true;
170 read_ahead=false;
171 errcode=4;
172 }
173 }
174
175 // Now let's check for block type
176 if ((!error)&&(!warning)&&!block->has_known_type()){
177 if (cfg_ignore_unknown_block_errors){
178 message="Warning: Unknown Block type!";
179 warning=true;
180 }else{
181 message="Error: Unknown Block type!";
182 error=true;
183 read_ahead=false;
184 errcode=5;
185 }
186 }
187
188 // Count block.
189 blocks_read++;
190 tape.insert(tape.end(),block);
191 block_start=read_pointer+block->get_discarded_bytes();
192 block_end=block_start+block->get_raw_size()-1;
193 read_pointer=block_end+1;
194
195 FILE * fp=stdwarn;
196 if (error) fp=stderr;
197
198 if (cfg_verbose||error||warning){
199 if (!spaced) fprintf(fp,"\n");
200 spaced=false;
201 fprintf(fp,"Block No.%03i: Start:0x%04x End:0x%04x Size:0x%02x\n",
202 blocks_read-1,
203 block_start,
204 block_end,
205 block->get_raw_size());
206 }
207
208 if (error) fprintf(stderr,message.c_str());
209 if (warning) fprintf(stdwarn,message.c_str());
210
211 if(error||warning){
212 dump_vector(block->get_description());
213 } else {
214 if(cfg_list_contents){
215 FILE * tmp_fp=fdopen(out_fd,"w");
216 dump_vector_fp(block->get_description(),tmp_fp);
217 if (!error&&!warning) spaced=false;
218 }
219 }
220
221 if (error||warning||cfg_verbose){
222 fprintf(fp,"\n");
223 spaced=true;
224 }
225 if (error) errors++;
226 if (warning) warnings++;
227 } // while....
228 if (cfg_verbose){
229 close(in_fd);
230 fprintf(stderr,"Reading finished.\n");
231 fprintf(stderr,"Bytes read:%i, Blocks read:%i\n",read_pointer,blocks_read);
232 }
233 } // read_tape()
234
235
236 /******************************************************************************/
237 /*!
238 *\brief Do integrity test and object or block dumps.
239 */
240 void process_tape(){
241 if (cfg_verbose) fprintf(stdwarn,"\nProcessing Data.\n");
242
243 bool in_object=false;
244 char filename[100];
245 char filename_numbered[100];
246 string objname;
247 int unknown_count=-1;
248 int fd=-1, fd_numbered=-1;
249 int obj_no=0;
250 int obj_start_block;
251
252 for (unsigned int i=0; i<tape.size();i++){
253 tape_block * block=tape[i];
254
255 if (block->get_type()==tape_block::TBT_EOT){
256 objname="EOT";
257 if (in_object){
258 if (cfg_ignore_object_integrity_errors){
259 fprintf(stdwarn,"Warning: Object integrity error!\
260 (Object no %i, Block %i unexpected)\n",obj_no,i);
261 warnings++;
262 } else {
263 fprintf(stderr,"Error: Object integrity error!\
264 (Object no %i, Block %i unexpected)\n",obj_no,i);
265 errors++;
266 errcode=6;
267 return;
268 }
269 }
270 }
271 if (!in_object){ // object begin
272
273 obj_no++;
274 obj_start_block=i;
275
276 objname="UNKNOWN";
277 unknown_count++;
278
279 vector<string>names=block->get_exported_symbols();
280 for (unsigned int a=0; a<names.size();a++){
281 objname=names[0];
282 if (objname!=" "){
283 objname=objname.substr(0,objname.find_last_not_of(" ")+1);
284 unknown_count--;
285 break;
286 }
287 }
288
289 if (block->get_type()==tape_block::TBT_EOT){
290 objname="EOT";
291 }
292
293 // Open file for split objects
294 if (cfg_split_objects && (block->get_type()!=tape_block::TBT_EOT)){
295 if (objname=="UNKNOWN")snprintf(filename,99,"UNKNOWN%02i",
296 unknown_count);
297 else snprintf(filename,99,"%s",objname.c_str());
298 if (fd>-1) close (fd);
299 if (cfg_verbose) fprintf(stdwarn,"Writing file: %s\n",filename);
300 fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0666);
301 if (fd<0){
302 fprintf(stderr,"Error: could not open file \"%s\" for writing!\n",
303 filename);
304 errors++;
305 errcode=1;
306 return;
307 }
308 }
309
310 // Open file for split objects numbered
311 snprintf(filename_numbered,99,"%03i0-%s",obj_no,objname.c_str());
312 if (cfg_split_objects_numbered){
313 close (fd_numbered);
314 if (cfg_verbose) fprintf(stdwarn,"Writing file: %s\n",filename_numbered);
315 fd_numbered=open(filename_numbered,O_WRONLY|O_CREAT|O_TRUNC,0666);
316 if (fd_numbered<0){
317 fprintf(stderr,"Error: could not open file \"%s\" for writing!\n",
318 filename_numbered);
319 errors++;
320 errcode=1;
321 return;
322 }
323 }
324 in_object=true;
325 } // object begin
326
327 // Output block data
328 if (cfg_split_objects){
329 try{
330 if (block->get_type()!=tape_block::TBT_EOT) // Don't want EOT here
331 block->dump_to_fd(fd);
332 }
333 catch (tape_block::io_error_exception e){
334 fprintf(stderr,"Error: could write to file \"%s\"!\n",
335 filename);
336 errors++;
337 errcode=1;
338 return;
339 }
340 } // if (cfg_split_objects)
341
342 // Output block data
343 if (cfg_split_objects_numbered){
344 try{
345 block->dump_to_fd(fd_numbered);
346 }
347 catch (tape_block::io_error_exception e){
348 fprintf(stderr,"Error: could write to file \"%s\"!\n",
349 filename_numbered);
350 errors++;
351 errcode=1;
352 return;
353 }
354 } // if (cfg_split_objects_numbered)
355
356 // Output individual block file if desired
357 if (cfg_split_blocks){
358 char fname[100];
359 snprintf(fname,99,"%03i0-%s-%03i.block",obj_no,objname.c_str(),
360 i-obj_start_block);
361 if (cfg_verbose) fprintf(stdwarn,"Writing file: %s\n",fname);
362 int fd_block=open(fname,O_WRONLY|O_TRUNC|O_CREAT,0666);
363 if (fd_block<0){
364 fprintf(stderr,"Error: could not open file \"%s\" for writing!\n",
365 fname);
366 errors++;
367 errcode=1;
368 close(fd);
369 close(fd_numbered);
370 return;
371 }
372 try{
373 block->dump_to_fd(fd_block);
374 }
375 catch (tape_block::io_error_exception e){
376 fprintf(stderr,"Error: could write to file \"%s\"!\n",
377 fname);
378 errors++;
379 errcode=1;
380 close(fd);
381 close(fd_numbered);
382 return;
383 }
384 close(fd_block);
385 }
386
387 if (block->is_endblock()||(block->get_type()==tape_block::TBT_EOT)) {
388 in_object=false;
389 close(fd);
390 close(fd_numbered);
391 }
392 } // for (...)
393
394 if (in_object){
395 if (cfg_ignore_object_integrity_errors){
396 fprintf(stdwarn,"Warning: Object integrity error! Last object incomplete!\n");
397 warnings++;
398 } else {
399 fprintf(stdwarn,"Error: Object integrity error! Last Object incomplete!\n");
400 errors++;
401 errcode=6;
402 if (fd!=-1) close(fd);
403 if (fd_numbered!=-1) close(fd_numbered);
404 return;
405 }
406 }
407 } // process_tape()
408
409 /******************************************************************************/
410 /*!
411 *\brief Everything that has to do with symbol listing.
412 */
413 void process_symbols(){
414 vector<string>exported;
415 vector<string>called;
416 vector <string>unsatisfied;
417
418 if (cfg_verbose) fprintf(stdwarn,"\nProcessing Symbols.\n");
419
420 for (unsigned int i=0; i<tape.size();i++){
421 merge_vector_unique(exported,tape[i]->get_exported_symbols());
422 merge_vector_unique(called,tape[i]->get_called_symbols());
423 }
424
425 for (unsigned int icalled=0;icalled<called.size();icalled++){
426 bool found=false;
427 for (unsigned int iexported=0;iexported<exported.size();iexported++){
428 if (exported[iexported].compare(called[icalled])==0){
429 found=true;
430 break;
431 }
432 }
433 if (!found) {
434 bool present=false;
435 for (unsigned int i=0;i<unsatisfied.size();i++){
436 if (unsatisfied[i].compare(called[icalled])==0){
437 present=true;
438 break;
439 }
440 }
441 if (!present) unsatisfied.insert(unsatisfied.end(),called[icalled]);
442 }
443 }
444
445 FILE * outp=fdopen(out_fd,"w");
446
447 if (cfg_output_called){
448 dump_vector_fp(called,outp);
449 }
450
451 if (cfg_output_exported){
452 dump_vector_fp(exported,outp);
453 }
454
455 if (cfg_output_unsatisfied){
456 dump_vector_fp(unsatisfied,outp);
457 }
458
459 } // process_symbols()
460
461 /******************************************************************************/
462 /*!
463 *\brief The main routine.
464 *
465 */
466 int main(int argc, char ** args){
467
468 // Do all the configuration stuff
469 do_config(argc,args);
470
471 // Output a version message if desired
472 if (cfg_version){
473 fprintf(stderr, ID_STRING, VERSION, BUILD_DATE, BUILD_STAMP);
474 exit(0);
475 }
476
477 // Assign warning output according to configuration
478 if (cfg_quiet) stdwarn=fopen("/dev/null","w");
479 else stdwarn=stderr;
480
481 read_tape(); // Process input to completion.
482 exit_on_error();
483
484 process_tape();
485 exit_on_error();
486
487 process_symbols();
488 exit_on_error();
489
490 if (warnings>0){
491 fprintf(stdwarn,"Warnings:%i\n",warnings);
492 return 99;
493 }
494 if (cfg_verbose) fprintf(stdwarn,"\nSuccess.\n");
495 return 0;
496
497 /*
498 * All over this program, no memory is freed. This is not necessary because
499 * everything is allocated once and that's it.
500 * The classes support proper freeing of their internal buffers.
501 */
502
503 } // main()
504
505 /******************************************************************************/