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