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