*** empty log message ***
[h316.git] / pc-tools / ldc2 / src / main.cpp
1 /******************************************************************************
2 *
3 * LDC2 source code
4 *
5 * $Date: 2008/08/25 21:02:24 $
6 * $Author: hachti $
7 *
8 * $Log: main.cpp,v $
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
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
18 * *** empty log message ***
19 *
20 * Revision 2.1 2007-03-26 01:15:21 hachti
21 * *** empty log message ***
22 *
23 * Revision 2.0 2007-03-26 01:00:40 hachti
24 * *** empty log message ***
25 *
26 *
27 ******************************************************************************/
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34
35 #include <vector>
36 #include <string>
37
38 #include "config.hh"
39 #include "tool.hh"
40
41 #include "tape_block.hh"
42 #include "data_block_0.hh"
43
44 using namespace std;
45
46 #ifndef BUILD_STAMP
47 #define BUILD_STAMP ""
48 #endif
49
50 #ifndef VERSION
51 #define VERSION "0.0"
52 #endif
53
54 #define ID_STRING "\n ldc2 - The X16 object tape analyser\n\
55 (C) 2007 Philipp Hachtmann\n\n\
56 Version %s, built %s\n %s\n\n"
57
58 /******************************************************************************/
59
60 static FILE * stdwarn; //! Suppressable warning output file pointer.
61 static vector<tape_block*> tape; //! The whole tape contents.
62 static vector<vector<tape_block*> > objects; //! Tape content in objects.
63
64 static int errors = 0; //! Global error counter.
65 static int warnings= 0; //! Global warning counter.
66 static int errcode = 0; //! Error code for error exit routine.
67
68
69 /******************************************************************************/
70 /*!
71 *\brief Error exit routine.
72 *
73 * This routine tests the global error counter and terminates the program
74 * if necessary.
75 */
76 void exit_on_error(){
77 if (errors){
78 fprintf(stderr,"Failed. (%i)\n",errcode);
79 exit(errcode);
80 }
81 }
82
83
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 */
94 void 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.
102
103 bool spaced=false; //! Help flag for spaced messages.
104
105 string message; //! A warning or help message.
106
107
108 while(read_ahead){
109
110 bool err_checksum=false; //! Checksum error flag.
111 bool err_integrity=false; //! Integrity error flag.
112
113 bool warning=false; //! Warning flag.
114 bool error=false; //! Error flag.
115
116 // Try to generate block
117 try{
118 block=tape_block::gen_from_fd(in_fd);
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){
127 if (in_fd){
128 fprintf(stderr,"Error: Could not read from \"%s\"!\n",
129 cfg_infile.c_str());
130 } else {
131 fprintf(stderr,"Error: Could not read from stdin!\n");
132 }
133 error=true;
134 errcode=2;
135 break; // Immediately leave read loop.
136 }
137
138 catch(tape_block::eof_illegal_exception &e){
139 block=e.get_block();
140 err_integrity=true;
141 read_ahead=false;
142 if (cfg_ignore_block_errors){
143 message="Warning: Block integrity check failed!\n";
144 warning=true;
145 } else {
146 message="Error: Block integrity check failed!\n";
147 error=true;
148 errcode=3;
149 }
150 }
151
152 catch(tape_block::checksum_error_exception &e){
153 block=e.get_block();
154 err_checksum=true;
155 if (cfg_ignore_checksum_errors){
156 message="Warning: Block checksum wrong!\n";
157 warning=true;
158 } else {
159 message="Error: Block checksum wrong!\n";
160 error=true;
161 read_ahead=false;
162 errcode=4;
163 }
164 }
165
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());
201
202 if(error||warning){
203 dump_vector(block->get_description());
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 }
210 }
211
212 if (error||warning||cfg_verbose){
213 fprintf(fp,"\n");
214 spaced=true;
215 }
216 if (error) errors++;
217 if (warning) warnings++;
218 } // while....
219 if (cfg_verbose){
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
226
227 /******************************************************************************/
228 /*!
229 *\brief Do integrity test and object or block dumps.
230 */
231 void process_tape(){
232 if (cfg_verbose) fprintf(stdwarn,"\nProcessing Data.\n");
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){
250 fprintf(stdwarn,"Warning: Object integrity error!\
251 (Object no %i, Block %i unexpected)\n",obj_no,i);
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 }
262 if (!in_object){ // object begin
263
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;
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)){
286 if (objname=="UNKNOWN")snprintf(filename,99,"UNKNOWN%02i",
287 unknown_count);
288 else snprintf(filename,99,"%s",objname.c_str());
289 if (fd>-1) close (fd);
290 if (cfg_verbose) fprintf(stdwarn,"Writing file: %s\n",filename);
291 fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0666);
292 if (fd<0){
293 fprintf(stderr,"Error: could not open file \"%s\" for writing!\n",
294 filename);
295 errors++;
296 errcode=1;
297 return;
298 }
299 }
300
301 // Open file for split objects numbered
302 snprintf(filename_numbered,99,"%03i0-%s",obj_no,objname.c_str());
303 if (cfg_split_objects_numbered){
304 close (fd_numbered);
305 if (cfg_verbose) fprintf(stdwarn,"Writing file: %s\n",filename_numbered);
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);
310 errors++;
311 errcode=1;
312 return;
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);
327 errors++;
328 errcode=1;
329 return;
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);
341 errors++;
342 errcode=1;
343 return;
344 }
345 } // if (cfg_split_objects_numbered)
346
347 // Output individual block file if desired
348 if (cfg_split_blocks){
349 char fname[100];
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);
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);
357 errors++;
358 errcode=1;
359 close(fd);
360 close(fd_numbered);
361 return;
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);
369 errors++;
370 errcode=1;
371 close(fd);
372 close(fd_numbered);
373 return;
374 }
375 close(fd_block);
376 }
377
378 if (block->is_endblock()||(block->get_type()==tape_block::TBT_EOT)) {
379 in_object=false;
380 close(fd);
381 close(fd_numbered);
382 }
383 } // for (...)
384
385 if (in_object){
386 if (cfg_ignore_object_integrity_errors){
387 fprintf(stdwarn,"Warning: Object integrity error! Last object incomplete!\n");
388 warnings++;
389 } else {
390 fprintf(stdwarn,"Error: Object integrity error! Last Object incomplete!\n");
391 errors++;
392 errcode=6;
393 if (fd!=-1) close(fd);
394 if (fd_numbered!=-1) close(fd_numbered);
395 return;
396 }
397 }
398 } // process_tape()
399
400 /******************************************************************************/
401 /*!
402 *\brief Everything that has to do with symbol listing.
403 */
404 void process_symbols(){
405 vector<string>exported;
406 vector<string>called;
407 vector <string>unsatisfied;
408
409 if (cfg_verbose) fprintf(stdwarn,"\nProcessing Symbols.\n");
410
411 for (unsigned int i=0; i<tape.size();i++){
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;
422 }
423 }
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 }
434 }
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
450 } // process_symbols()
451
452 /******************************************************************************/
453 /*!
454 *\brief The main routine.
455 *
456 */
457 int main(int argc, char ** args){
458
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
475 process_tape();
476 exit_on_error();
477
478 process_symbols();
479 exit_on_error();
480
481 if (warnings>0){
482 fprintf(stdwarn,"Warnings:%i\n",warnings);
483 return 99;
484 }
485 if (cfg_verbose) fprintf(stdwarn,"\nSuccess.\n");
486 return 0;
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
494 } // main()
495
496 /******************************************************************************/