ldc2: Cosmetic fixes and support for compiler orverride
[h316.git] / pc-tools / ldc2 / src / main.cpp
CommitLineData
4741aa72 1/******************************************************************************
2 *
3 * LDC2 source code
4 *
7023c3ab 5 * $Date: 2010/01/04 02:10:59 $
4741aa72 6 * $Author: hachti $
7 *
8 * $Log: main.cpp,v $
7023c3ab 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
7ced2dbe 13 * Added some includes
14 *
15 * Revision 2.4 2008-08-25 21:02:24 hachti
eabafcca 16 * *** empty log message ***
17 *
18 * Revision 2.3 2007-05-30 02:51:16 hachti
fe67c7be 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
d65ad4d7 24 * *** empty log message ***
25 *
26 * Revision 2.1 2007-03-26 01:15:21 hachti
09c71e8a 27 * *** empty log message ***
28 *
29 * Revision 2.0 2007-03-26 01:00:40 hachti
4741aa72 30 * *** empty log message ***
31 *
32 *
33 ******************************************************************************/
34
de6b6757 35#include <sys/types.h>
36#include <sys/stat.h>
37#include <fcntl.h>
eabafcca 38#include <unistd.h>
39#include <stdlib.h>
7023c3ab 40#include <stdio.h>
7ced2dbe 41#include <stdlib.h>
42
43
798b0c1d 44#include <vector>
45#include <string>
09c71e8a 46
ea4c19a4 47#include "config.hh"
48#include "tool.hh"
97b26985 49
50#include "tape_block.hh"
fed2c751 51#include "data_block_0.hh"
52
798b0c1d 53using namespace std;
54
7880ae2d 55#ifndef BUILD_STAMP
56#define BUILD_STAMP ""
57#endif
58
59#ifndef VERSION
60#define VERSION "0.0"
61#endif
62
874a2bd8 63#define ID_STRING "\n ldc2 - The X16 object tape analyser\n\
7880ae2d 64 (C) 2007 Philipp Hachtmann\n\n\
65 Version %s, built %s\n %s\n\n"
66
874a2bd8 67/******************************************************************************/
7880ae2d 68
d65ad4d7 69static FILE * stdwarn; //! Suppressable warning output file pointer.
70static vector<tape_block*> tape; //! The whole tape contents.
874a2bd8 71static vector<vector<tape_block*> > objects; //! Tape content in objects.
7880ae2d 72
d65ad4d7 73static int errors = 0; //! Global error counter.
74static int warnings= 0; //! Global warning counter.
75static int errcode = 0; //! Error code for error exit routine.
76
7880ae2d 77
09c71e8a 78/******************************************************************************/
79/*!
80 *\brief Error exit routine.
81 *
82 * This routine tests the global error counter and terminates the program
83 * if necessary.
84 */
874a2bd8 85void exit_on_error(){
86 if (errors){
87 fprintf(stderr,"Failed. (%i)\n",errcode);
88 exit(errcode);
7880ae2d 89 }
874a2bd8 90}
d65ad4d7 91
909d3603 92
874a2bd8 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 */
103void 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.
ad324d29 111
874a2bd8 112 bool spaced=false; //! Help flag for spaced messages.
113
114 string message; //! A warning or help message.
7880ae2d 115
874a2bd8 116
fed2c751 117 while(read_ahead){
874a2bd8 118
0f7b7e09
PH
119 // bool err_checksum=false; //! Checksum error flag.
120 // bool err_integrity=false; //! Integrity error flag.
874a2bd8 121
d65ad4d7 122 bool warning=false; //! Warning flag.
123 bool error=false; //! Error flag.
874a2bd8 124
d65ad4d7 125 // Try to generate block
7880ae2d 126 try{
127 block=tape_block::gen_from_fd(in_fd);
7880ae2d 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){
fed2c751 136 if (in_fd){
d65ad4d7 137 fprintf(stderr,"Error: Could not read from \"%s\"!\n",
138 cfg_infile.c_str());
fed2c751 139 } else {
7880ae2d 140 fprintf(stderr,"Error: Could not read from stdin!\n");
fed2c751 141 }
874a2bd8 142 error=true;
fed2c751 143 errcode=2;
7880ae2d 144 break; // Immediately leave read loop.
145 }
146
147 catch(tape_block::eof_illegal_exception &e){
148 block=e.get_block();
0f7b7e09 149 // err_integrity=true;
874a2bd8 150 read_ahead=false;
7880ae2d 151 if (cfg_ignore_block_errors){
874a2bd8 152 message="Warning: Block integrity check failed!\n";
153 warning=true;
7880ae2d 154 } else {
874a2bd8 155 message="Error: Block integrity check failed!\n";
156 error=true;
7880ae2d 157 errcode=3;
fed2c751 158 }
7880ae2d 159 }
160
161 catch(tape_block::checksum_error_exception &e){
162 block=e.get_block();
0f7b7e09 163 // err_checksum=true;
7880ae2d 164 if (cfg_ignore_checksum_errors){
874a2bd8 165 message="Warning: Block checksum wrong!\n";
166 warning=true;
fed2c751 167 } else {
874a2bd8 168 message="Error: Block checksum wrong!\n";
169 error=true;
7880ae2d 170 read_ahead=false;
171 errcode=4;
fed2c751 172 }
7880ae2d 173 }
174
874a2bd8 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());
de6b6757 210
211 if(error||warning){
874a2bd8 212 dump_vector(block->get_description());
de6b6757 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 }
874a2bd8 219 }
7880ae2d 220
874a2bd8 221 if (error||warning||cfg_verbose){
222 fprintf(fp,"\n");
223 spaced=true;
224 }
225 if (error) errors++;
226 if (warning) warnings++;
227 } // while....
7880ae2d 228 if (cfg_verbose){
874a2bd8 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
de6b6757 235
874a2bd8 236/******************************************************************************/
d65ad4d7 237/*!
238 *\brief Do integrity test and object or block dumps.
239 */
de6b6757 240void process_tape(){
d65ad4d7 241 if (cfg_verbose) fprintf(stdwarn,"\nProcessing Data.\n");
de6b6757 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){
d65ad4d7 259 fprintf(stdwarn,"Warning: Object integrity error!\
260 (Object no %i, Block %i unexpected)\n",obj_no,i);
de6b6757 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 }
de6b6757 271 if (!in_object){ // object begin
d65ad4d7 272
de6b6757 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;
de6b6757 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)){
fe67c7be 295 if (objname=="UNKNOWN")snprintf(filename,99,"UNKNOWN%02i",
d65ad4d7 296 unknown_count);
fe67c7be 297 else snprintf(filename,99,"%s",objname.c_str());
de6b6757 298 if (fd>-1) close (fd);
d65ad4d7 299 if (cfg_verbose) fprintf(stdwarn,"Writing file: %s\n",filename);
de6b6757 300 fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0666);
de6b6757 301 if (fd<0){
302 fprintf(stderr,"Error: could not open file \"%s\" for writing!\n",
303 filename);
09c71e8a 304 errors++;
305 errcode=1;
306 return;
de6b6757 307 }
308 }
309
310 // Open file for split objects numbered
fe67c7be 311 snprintf(filename_numbered,99,"%03i0-%s",obj_no,objname.c_str());
de6b6757 312 if (cfg_split_objects_numbered){
d65ad4d7 313 close (fd_numbered);
314 if (cfg_verbose) fprintf(stdwarn,"Writing file: %s\n",filename_numbered);
de6b6757 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);
09c71e8a 319 errors++;
320 errcode=1;
321 return;
de6b6757 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);
09c71e8a 336 errors++;
337 errcode=1;
338 return;
de6b6757 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);
09c71e8a 350 errors++;
351 errcode=1;
352 return;
de6b6757 353 }
354 } // if (cfg_split_objects_numbered)
355
356 // Output individual block file if desired
357 if (cfg_split_blocks){
358 char fname[100];
d65ad4d7 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);
de6b6757 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);
09c71e8a 366 errors++;
367 errcode=1;
d65ad4d7 368 close(fd);
369 close(fd_numbered);
09c71e8a 370 return;
de6b6757 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);
09c71e8a 378 errors++;
379 errcode=1;
d65ad4d7 380 close(fd);
381 close(fd_numbered);
09c71e8a 382 return;
de6b6757 383 }
384 close(fd_block);
385 }
386
387 if (block->is_endblock()||(block->get_type()==tape_block::TBT_EOT)) {
388 in_object=false;
d65ad4d7 389 close(fd);
390 close(fd_numbered);
de6b6757 391 }
392 } // for (...)
393
394 if (in_object){
395 if (cfg_ignore_object_integrity_errors){
d65ad4d7 396 fprintf(stdwarn,"Warning: Object integrity error! Last object incomplete!\n");
de6b6757 397 warnings++;
398 } else {
d65ad4d7 399 fprintf(stdwarn,"Error: Object integrity error! Last Object incomplete!\n");
de6b6757 400 errors++;
401 errcode=6;
d65ad4d7 402 if (fd!=-1) close(fd);
403 if (fd_numbered!=-1) close(fd_numbered);
de6b6757 404 return;
405 }
406 }
de6b6757 407} // process_tape()
874a2bd8 408
09c71e8a 409/******************************************************************************/
410/*!
411 *\brief Everything that has to do with symbol listing.
412 */
d65ad4d7 413void process_symbols(){
de6b6757 414 vector<string>exported;
415 vector<string>called;
416 vector <string>unsatisfied;
d65ad4d7 417
418 if (cfg_verbose) fprintf(stdwarn,"\nProcessing Symbols.\n");
419
874a2bd8 420 for (unsigned int i=0; i<tape.size();i++){
de6b6757 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;
874a2bd8 431 }
432 }
de6b6757 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 }
7880ae2d 443 }
de6b6757 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
d65ad4d7 459} // process_symbols()
ad324d29 460
874a2bd8 461/******************************************************************************/
462/*!
463 *\brief The main routine.
09c71e8a 464 *
874a2bd8 465 */
466int main(int argc, char ** args){
7880ae2d 467
874a2bd8 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
de6b6757 484 process_tape();
485 exit_on_error();
486
d65ad4d7 487 process_symbols();
de6b6757 488 exit_on_error();
d65ad4d7 489
de6b6757 490 if (warnings>0){
491 fprintf(stdwarn,"Warnings:%i\n",warnings);
492 return 99;
874a2bd8 493 }
d65ad4d7 494 if (cfg_verbose) fprintf(stdwarn,"\nSuccess.\n");
ad324d29 495 return 0;
d65ad4d7 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
ad324d29 503} // main()
798b0c1d 504
d65ad4d7 505/******************************************************************************/