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