Changed everything towards LDC2 use.
[h316.git] / pc-tools / ldc2 / src / main.cpp
1 /******************************************************************************
2 *
3 * LDC2 source code
4 *
5 * $Date: 2007/05/30 02:51:16 $
6 * $Author: hachti $
7 *
8 * $Log: main.cpp,v $
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
15 * *** empty log message ***
16 *
17 * Revision 2.1 2007-03-26 01:15:21 hachti
18 * *** empty log message ***
19 *
20 * Revision 2.0 2007-03-26 01:00:40 hachti
21 * *** empty log message ***
22 *
23 *
24 ******************************************************************************/
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29
30 #include <vector>
31 #include <string>
32
33 #include "config.hh"
34 #include "tool.hh"
35
36 #include "tape_block.hh"
37 #include "data_block_0.hh"
38
39 using namespace std;
40
41 #ifndef BUILD_STAMP
42 #define BUILD_STAMP ""
43 #endif
44
45 #ifndef VERSION
46 #define VERSION "0.0"
47 #endif
48
49 #define ID_STRING "\n ldc2 - The X16 object tape analyser\n\
50 (C) 2007 Philipp Hachtmann\n\n\
51 Version %s, built %s\n %s\n\n"
52
53 /******************************************************************************/
54
55 static FILE * stdwarn; //! Suppressable warning output file pointer.
56 static vector<tape_block*> tape; //! The whole tape contents.
57 static vector<vector<tape_block*> > objects; //! Tape content in objects.
58
59 static int errors = 0; //! Global error counter.
60 static int warnings= 0; //! Global warning counter.
61 static int errcode = 0; //! Error code for error exit routine.
62
63
64 /******************************************************************************/
65 /*!
66 *\brief Error exit routine.
67 *
68 * This routine tests the global error counter and terminates the program
69 * if necessary.
70 */
71 void exit_on_error(){
72 if (errors){
73 fprintf(stderr,"Failed. (%i)\n",errcode);
74 exit(errcode);
75 }
76 }
77
78
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 */
89 void 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.
97
98 bool spaced=false; //! Help flag for spaced messages.
99
100 string message; //! A warning or help message.
101
102
103 while(read_ahead){
104
105 bool err_checksum=false; //! Checksum error flag.
106 bool err_integrity=false; //! Integrity error flag.
107
108 bool warning=false; //! Warning flag.
109 bool error=false; //! Error flag.
110
111 // Try to generate block
112 try{
113 block=tape_block::gen_from_fd(in_fd);
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){
122 if (in_fd){
123 fprintf(stderr,"Error: Could not read from \"%s\"!\n",
124 cfg_infile.c_str());
125 } else {
126 fprintf(stderr,"Error: Could not read from stdin!\n");
127 }
128 error=true;
129 errcode=2;
130 break; // Immediately leave read loop.
131 }
132
133 catch(tape_block::eof_illegal_exception &e){
134 block=e.get_block();
135 err_integrity=true;
136 read_ahead=false;
137 if (cfg_ignore_block_errors){
138 message="Warning: Block integrity check failed!\n";
139 warning=true;
140 } else {
141 message="Error: Block integrity check failed!\n";
142 error=true;
143 errcode=3;
144 }
145 }
146
147 catch(tape_block::checksum_error_exception &e){
148 block=e.get_block();
149 err_checksum=true;
150 if (cfg_ignore_checksum_errors){
151 message="Warning: Block checksum wrong!\n";
152 warning=true;
153 } else {
154 message="Error: Block checksum wrong!\n";
155 error=true;
156 read_ahead=false;
157 errcode=4;
158 }
159 }
160
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());
196
197 if(error||warning){
198 dump_vector(block->get_description());
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 }
205 }
206
207 if (error||warning||cfg_verbose){
208 fprintf(fp,"\n");
209 spaced=true;
210 }
211 if (error) errors++;
212 if (warning) warnings++;
213 } // while....
214 if (cfg_verbose){
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
221
222 /******************************************************************************/
223 /*!
224 *\brief Do integrity test and object or block dumps.
225 */
226 void process_tape(){
227 if (cfg_verbose) fprintf(stdwarn,"\nProcessing Data.\n");
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){
245 fprintf(stdwarn,"Warning: Object integrity error!\
246 (Object no %i, Block %i unexpected)\n",obj_no,i);
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 }
257 if (!in_object){ // object begin
258
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;
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)){
281 if (objname=="UNKNOWN")snprintf(filename,99,"UNKNOWN%02i",
282 unknown_count);
283 else snprintf(filename,99,"%s",objname.c_str());
284 if (fd>-1) close (fd);
285 if (cfg_verbose) fprintf(stdwarn,"Writing file: %s\n",filename);
286 fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0666);
287 if (fd<0){
288 fprintf(stderr,"Error: could not open file \"%s\" for writing!\n",
289 filename);
290 errors++;
291 errcode=1;
292 return;
293 }
294 }
295
296 // Open file for split objects numbered
297 snprintf(filename_numbered,99,"%03i0-%s",obj_no,objname.c_str());
298 if (cfg_split_objects_numbered){
299 close (fd_numbered);
300 if (cfg_verbose) fprintf(stdwarn,"Writing file: %s\n",filename_numbered);
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);
305 errors++;
306 errcode=1;
307 return;
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);
322 errors++;
323 errcode=1;
324 return;
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);
336 errors++;
337 errcode=1;
338 return;
339 }
340 } // if (cfg_split_objects_numbered)
341
342 // Output individual block file if desired
343 if (cfg_split_blocks){
344 char fname[100];
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);
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);
352 errors++;
353 errcode=1;
354 close(fd);
355 close(fd_numbered);
356 return;
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);
364 errors++;
365 errcode=1;
366 close(fd);
367 close(fd_numbered);
368 return;
369 }
370 close(fd_block);
371 }
372
373 if (block->is_endblock()||(block->get_type()==tape_block::TBT_EOT)) {
374 in_object=false;
375 close(fd);
376 close(fd_numbered);
377 }
378 } // for (...)
379
380 if (in_object){
381 if (cfg_ignore_object_integrity_errors){
382 fprintf(stdwarn,"Warning: Object integrity error! Last object incomplete!\n");
383 warnings++;
384 } else {
385 fprintf(stdwarn,"Error: Object integrity error! Last Object incomplete!\n");
386 errors++;
387 errcode=6;
388 if (fd!=-1) close(fd);
389 if (fd_numbered!=-1) close(fd_numbered);
390 return;
391 }
392 }
393 } // process_tape()
394
395 /******************************************************************************/
396 /*!
397 *\brief Everything that has to do with symbol listing.
398 */
399 void process_symbols(){
400 vector<string>exported;
401 vector<string>called;
402 vector <string>unsatisfied;
403
404 if (cfg_verbose) fprintf(stdwarn,"\nProcessing Symbols.\n");
405
406 for (unsigned int i=0; i<tape.size();i++){
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;
417 }
418 }
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 }
429 }
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
445 } // process_symbols()
446
447 /******************************************************************************/
448 /*!
449 *\brief The main routine.
450 *
451 */
452 int main(int argc, char ** args){
453
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
470 process_tape();
471 exit_on_error();
472
473 process_symbols();
474 exit_on_error();
475
476 if (warnings>0){
477 fprintf(stdwarn,"Warnings:%i\n",warnings);
478 return 99;
479 }
480 if (cfg_verbose) fprintf(stdwarn,"\nSuccess.\n");
481 return 0;
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
489 } // main()
490
491 /******************************************************************************/