*** empty log message ***
[h316.git] / pc-tools / ldc2 / src / main.cpp
CommitLineData
4741aa72 1/******************************************************************************
2 *
3 * LDC2 source code
4 *
09c71e8a 5 * $Date: 2007/03/26 01:15:21 $
4741aa72 6 * $Author: hachti $
7 *
8 * $Log: main.cpp,v $
09c71e8a 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
4741aa72 13 * *** empty log message ***
14 *
15 *
16 ******************************************************************************/
17
de6b6757 18#include <sys/types.h>
19#include <sys/stat.h>
20#include <fcntl.h>
7880ae2d 21
798b0c1d 22#include <vector>
23#include <string>
09c71e8a 24
ea4c19a4 25#include "config.hh"
26#include "tool.hh"
97b26985 27
28#include "tape_block.hh"
fed2c751 29#include "data_block_0.hh"
30
798b0c1d 31using namespace std;
32
7880ae2d 33#ifndef BUILD_STAMP
34#define BUILD_STAMP ""
35#endif
36
37#ifndef VERSION
38#define VERSION "0.0"
39#endif
40
874a2bd8 41#define ID_STRING "\n ldc2 - The X16 object tape analyser\n\
7880ae2d 42 (C) 2007 Philipp Hachtmann\n\n\
43 Version %s, built %s\n %s\n\n"
44
874a2bd8 45/******************************************************************************/
7880ae2d 46
874a2bd8 47static FILE * stdwarn; //! Suppressable warning output file pointer.
48static vector<tape_block*> tape; //! Represents the whole tape contents.
49static vector<vector<tape_block*> > objects; //! Tape content in objects.
7880ae2d 50
874a2bd8 51static int errors=0;
52static int warnings=0;
53static int errcode=0; //! Variable for error codes.
7880ae2d 54
09c71e8a 55/******************************************************************************/
56/*!
57 *\brief Error exit routine.
58 *
59 * This routine tests the global error counter and terminates the program
60 * if necessary.
61 */
874a2bd8 62void exit_on_error(){
63 if (errors){
64 fprintf(stderr,"Failed. (%i)\n",errcode);
65 exit(errcode);
7880ae2d 66 }
874a2bd8 67}
909d3603 68
874a2bd8 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 */
79void 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.
ad324d29 87
874a2bd8 88 bool spaced=false; //! Help flag for spaced messages.
89
90 string message; //! A warning or help message.
7880ae2d 91
874a2bd8 92
fed2c751 93 while(read_ahead){
874a2bd8 94
95 bool err_checksum=false;
96 bool err_integrity=false;
97
98 bool warning=false;
99 bool error=false;
100
7880ae2d 101 try{
102 block=tape_block::gen_from_fd(in_fd);
7880ae2d 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){
fed2c751 111 if (in_fd){
7880ae2d 112 fprintf(stderr,"Error: Could not read from \"%s\"!\n",cfg_infile.c_str());
fed2c751 113 } else {
7880ae2d 114 fprintf(stderr,"Error: Could not read from stdin!\n");
fed2c751 115 }
874a2bd8 116 error=true;
fed2c751 117 errcode=2;
7880ae2d 118 break; // Immediately leave read loop.
119 }
120
121 catch(tape_block::eof_illegal_exception &e){
122 block=e.get_block();
874a2bd8 123 err_integrity=true;
124 read_ahead=false;
7880ae2d 125 if (cfg_ignore_block_errors){
874a2bd8 126 message="Warning: Block integrity check failed!\n";
127 warning=true;
7880ae2d 128 } else {
874a2bd8 129 message="Error: Block integrity check failed!\n";
130 error=true;
7880ae2d 131 errcode=3;
fed2c751 132 }
7880ae2d 133 }
134
135 catch(tape_block::checksum_error_exception &e){
136 block=e.get_block();
874a2bd8 137 err_checksum=true;
7880ae2d 138 if (cfg_ignore_checksum_errors){
874a2bd8 139 message="Warning: Block checksum wrong!\n";
140 warning=true;
fed2c751 141 } else {
874a2bd8 142 message="Error: Block checksum wrong!\n";
143 error=true;
7880ae2d 144 read_ahead=false;
145 errcode=4;
fed2c751 146 }
7880ae2d 147 }
148
874a2bd8 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());
de6b6757 184
185 if(error||warning){
874a2bd8 186 dump_vector(block->get_description());
de6b6757 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 }
874a2bd8 193 }
7880ae2d 194
874a2bd8 195 if (error||warning||cfg_verbose){
196 fprintf(fp,"\n");
197 spaced=true;
198 }
199 if (error) errors++;
200 if (warning) warnings++;
201 } // while....
7880ae2d 202 if (cfg_verbose){
874a2bd8 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
de6b6757 209
874a2bd8 210/******************************************************************************/
de6b6757 211void 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);
09c71e8a 274 errors++;
275 errcode=1;
276 return;
de6b6757 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);
09c71e8a 288 errors++;
289 errcode=1;
290 return;
de6b6757 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);
09c71e8a 305 errors++;
306 errcode=1;
307 return;
de6b6757 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);
09c71e8a 319 errors++;
320 errcode=1;
321 return;
de6b6757 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);
09c71e8a 333 errors++;
334 errcode=1;
335 return;
de6b6757 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);
09c71e8a 343 errors++;
344 errcode=1;
345 return;
de6b6757 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 }
de6b6757 368} // process_tape()
874a2bd8 369
09c71e8a 370/******************************************************************************/
371/*!
372 *\brief Everything that has to do with symbol listing.
373 */
de6b6757 374void process_called_imports(){
375 vector<string>exported;
376 vector<string>called;
377 vector <string>unsatisfied;
378
874a2bd8 379 for (unsigned int i=0; i<tape.size();i++){
de6b6757 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;
874a2bd8 390 }
391 }
de6b6757 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 }
7880ae2d 402 }
de6b6757 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}
ad324d29 419
874a2bd8 420/******************************************************************************/
421/*!
422 *\brief The main routine.
09c71e8a 423 *
874a2bd8 424 */
425int main(int argc, char ** args){
7880ae2d 426
874a2bd8 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
de6b6757 443 process_tape();
444 exit_on_error();
445
446 process_called_imports();
447 exit_on_error();
874a2bd8 448
449
de6b6757 450 if (warnings>0){
451 fprintf(stdwarn,"Warnings:%i\n",warnings);
452 return 99;
874a2bd8 453 }
de6b6757 454 if (cfg_verbose) fprintf(stdwarn,"Success.\n");
ad324d29 455 return 0;
456} // main()
798b0c1d 457