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