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