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