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