Added some includes
[h316.git] / pc-tools / ldc2 / src / main.cpp
1 /******************************************************************************
2 *
3 * LDC2 source code
4 *
5 * $Date: 2008/10/01 13:30:14 $
6 * $Author: hachti $
7 *
8 * $Log: main.cpp,v $
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
13 * *** empty log message ***
14 *
15 * Revision 2.3 2007-05-30 02:51:16 hachti
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
21 * *** empty log message ***
22 *
23 * Revision 2.1 2007-03-26 01:15:21 hachti
24 * *** empty log message ***
25 *
26 * Revision 2.0 2007-03-26 01:00:40 hachti
27 * *** empty log message ***
28 *
29 *
30 ******************************************************************************/
31
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37
38 #include <stdlib.h>
39
40
41 #include <vector>
42 #include <string>
43
44 #include "config.hh"
45 #include "tool.hh"
46
47 #include "tape_block.hh"
48 #include "data_block_0.hh"
49
50 using namespace std;
51
52 #ifndef BUILD_STAMP
53 #define BUILD_STAMP ""
54 #endif
55
56 #ifndef VERSION
57 #define VERSION "0.0"
58 #endif
59
60 #define ID_STRING "\n ldc2 - The X16 object tape analyser\n\
61 (C) 2007 Philipp Hachtmann\n\n\
62 Version %s, built %s\n %s\n\n"
63
64 /******************************************************************************/
65
66 static FILE * stdwarn; //! Suppressable warning output file pointer.
67 static vector<tape_block*> tape; //! The whole tape contents.
68 static vector<vector<tape_block*> > objects; //! Tape content in objects.
69
70 static int errors = 0; //! Global error counter.
71 static int warnings= 0; //! Global warning counter.
72 static int errcode = 0; //! Error code for error exit routine.
73
74
75 /******************************************************************************/
76 /*!
77 *\brief Error exit routine.
78 *
79 * This routine tests the global error counter and terminates the program
80 * if necessary.
81 */
82 void exit_on_error(){
83 if (errors){
84 fprintf(stderr,"Failed. (%i)\n",errcode);
85 exit(errcode);
86 }
87 }
88
89
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 */
100 void 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.
108
109 bool spaced=false; //! Help flag for spaced messages.
110
111 string message; //! A warning or help message.
112
113
114 while(read_ahead){
115
116 bool err_checksum=false; //! Checksum error flag.
117 bool err_integrity=false; //! Integrity error flag.
118
119 bool warning=false; //! Warning flag.
120 bool error=false; //! Error flag.
121
122 // Try to generate block
123 try{
124 block=tape_block::gen_from_fd(in_fd);
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){
133 if (in_fd){
134 fprintf(stderr,"Error: Could not read from \"%s\"!\n",
135 cfg_infile.c_str());
136 } else {
137 fprintf(stderr,"Error: Could not read from stdin!\n");
138 }
139 error=true;
140 errcode=2;
141 break; // Immediately leave read loop.
142 }
143
144 catch(tape_block::eof_illegal_exception &e){
145 block=e.get_block();
146 err_integrity=true;
147 read_ahead=false;
148 if (cfg_ignore_block_errors){
149 message="Warning: Block integrity check failed!\n";
150 warning=true;
151 } else {
152 message="Error: Block integrity check failed!\n";
153 error=true;
154 errcode=3;
155 }
156 }
157
158 catch(tape_block::checksum_error_exception &e){
159 block=e.get_block();
160 err_checksum=true;
161 if (cfg_ignore_checksum_errors){
162 message="Warning: Block checksum wrong!\n";
163 warning=true;
164 } else {
165 message="Error: Block checksum wrong!\n";
166 error=true;
167 read_ahead=false;
168 errcode=4;
169 }
170 }
171
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());
207
208 if(error||warning){
209 dump_vector(block->get_description());
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 }
216 }
217
218 if (error||warning||cfg_verbose){
219 fprintf(fp,"\n");
220 spaced=true;
221 }
222 if (error) errors++;
223 if (warning) warnings++;
224 } // while....
225 if (cfg_verbose){
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
232
233 /******************************************************************************/
234 /*!
235 *\brief Do integrity test and object or block dumps.
236 */
237 void process_tape(){
238 if (cfg_verbose) fprintf(stdwarn,"\nProcessing Data.\n");
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){
256 fprintf(stdwarn,"Warning: Object integrity error!\
257 (Object no %i, Block %i unexpected)\n",obj_no,i);
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 }
268 if (!in_object){ // object begin
269
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;
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)){
292 if (objname=="UNKNOWN")snprintf(filename,99,"UNKNOWN%02i",
293 unknown_count);
294 else snprintf(filename,99,"%s",objname.c_str());
295 if (fd>-1) close (fd);
296 if (cfg_verbose) fprintf(stdwarn,"Writing file: %s\n",filename);
297 fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0666);
298 if (fd<0){
299 fprintf(stderr,"Error: could not open file \"%s\" for writing!\n",
300 filename);
301 errors++;
302 errcode=1;
303 return;
304 }
305 }
306
307 // Open file for split objects numbered
308 snprintf(filename_numbered,99,"%03i0-%s",obj_no,objname.c_str());
309 if (cfg_split_objects_numbered){
310 close (fd_numbered);
311 if (cfg_verbose) fprintf(stdwarn,"Writing file: %s\n",filename_numbered);
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);
316 errors++;
317 errcode=1;
318 return;
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);
333 errors++;
334 errcode=1;
335 return;
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);
347 errors++;
348 errcode=1;
349 return;
350 }
351 } // if (cfg_split_objects_numbered)
352
353 // Output individual block file if desired
354 if (cfg_split_blocks){
355 char fname[100];
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);
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);
363 errors++;
364 errcode=1;
365 close(fd);
366 close(fd_numbered);
367 return;
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);
375 errors++;
376 errcode=1;
377 close(fd);
378 close(fd_numbered);
379 return;
380 }
381 close(fd_block);
382 }
383
384 if (block->is_endblock()||(block->get_type()==tape_block::TBT_EOT)) {
385 in_object=false;
386 close(fd);
387 close(fd_numbered);
388 }
389 } // for (...)
390
391 if (in_object){
392 if (cfg_ignore_object_integrity_errors){
393 fprintf(stdwarn,"Warning: Object integrity error! Last object incomplete!\n");
394 warnings++;
395 } else {
396 fprintf(stdwarn,"Error: Object integrity error! Last Object incomplete!\n");
397 errors++;
398 errcode=6;
399 if (fd!=-1) close(fd);
400 if (fd_numbered!=-1) close(fd_numbered);
401 return;
402 }
403 }
404 } // process_tape()
405
406 /******************************************************************************/
407 /*!
408 *\brief Everything that has to do with symbol listing.
409 */
410 void process_symbols(){
411 vector<string>exported;
412 vector<string>called;
413 vector <string>unsatisfied;
414
415 if (cfg_verbose) fprintf(stdwarn,"\nProcessing Symbols.\n");
416
417 for (unsigned int i=0; i<tape.size();i++){
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;
428 }
429 }
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 }
440 }
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
456 } // process_symbols()
457
458 /******************************************************************************/
459 /*!
460 *\brief The main routine.
461 *
462 */
463 int main(int argc, char ** args){
464
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
481 process_tape();
482 exit_on_error();
483
484 process_symbols();
485 exit_on_error();
486
487 if (warnings>0){
488 fprintf(stdwarn,"Warnings:%i\n",warnings);
489 return 99;
490 }
491 if (cfg_verbose) fprintf(stdwarn,"\nSuccess.\n");
492 return 0;
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
500 } // main()
501
502 /******************************************************************************/