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