*** empty log message ***
[h316.git] / pc-tools / ldc2 / src / main.cpp
1 /* ldc2 preliminary main program */
2
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <fcntl.h>
6
7 #include <vector>
8 #include <string>
9
10 #include "config.hh"
11 #include "tool.hh"
12
13 #include "tape_block.hh"
14 #include "data_block_0.hh"
15
16 using namespace std;
17
18 #ifndef BUILD_STAMP
19 #define BUILD_STAMP ""
20 #endif
21
22 #ifndef VERSION
23 #define VERSION "0.0"
24 #endif
25
26 #define ID_STRING "\n ldc2 - The X16 object tape analyser\n\
27 (C) 2007 Philipp Hachtmann\n\n\
28 Version %s, built %s\n %s\n\n"
29
30 /******************************************************************************/
31
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.
35
36 static int errors=0;
37 static int warnings=0;
38 static int errcode=0; //! Variable for error codes.
39
40
41 void exit_on_error(){
42 if (errors){
43 fprintf(stderr,"Failed. (%i)\n",errcode);
44 exit(errcode);
45 }
46 }
47
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.
66
67 bool spaced=false; //! Help flag for spaced messages.
68
69 string message; //! A warning or help message.
70
71
72 while(read_ahead){
73
74 bool err_checksum=false;
75 bool err_integrity=false;
76
77 bool warning=false;
78 bool error=false;
79
80 try{
81 block=tape_block::gen_from_fd(in_fd);
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){
90 if (in_fd){
91 fprintf(stderr,"Error: Could not read from \"%s\"!\n",cfg_infile.c_str());
92 } else {
93 fprintf(stderr,"Error: Could not read from stdin!\n");
94 }
95 error=true;
96 errcode=2;
97 break; // Immediately leave read loop.
98 }
99
100 catch(tape_block::eof_illegal_exception &e){
101 block=e.get_block();
102 err_integrity=true;
103 read_ahead=false;
104 if (cfg_ignore_block_errors){
105 message="Warning: Block integrity check failed!\n";
106 warning=true;
107 } else {
108 message="Error: Block integrity check failed!\n";
109 error=true;
110 errcode=3;
111 }
112 }
113
114 catch(tape_block::checksum_error_exception &e){
115 block=e.get_block();
116 err_checksum=true;
117 if (cfg_ignore_checksum_errors){
118 message="Warning: Block checksum wrong!\n";
119 warning=true;
120 } else {
121 message="Error: Block checksum wrong!\n";
122 error=true;
123 read_ahead=false;
124 errcode=4;
125 }
126 }
127
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());
163
164 if(error||warning){
165 dump_vector(block->get_description());
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 }
172 }
173
174 if (error||warning||cfg_verbose){
175 fprintf(fp,"\n");
176 spaced=true;
177 }
178 if (error) errors++;
179 if (warning) warnings++;
180 } // while....
181 if (cfg_verbose){
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
188
189 /******************************************************************************/
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
336
337 } // process_tape()
338
339 void process_called_imports(){
340 vector<string>exported;
341 vector<string>called;
342 vector <string>unsatisfied;
343
344 for (unsigned int i=0; i<tape.size();i++){
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;
355 }
356 }
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 }
367 }
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 }
384
385 /******************************************************************************/
386 /*!
387 *\brief The main routine.
388 */
389 int main(int argc, char ** args){
390
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
407 process_tape();
408 exit_on_error();
409
410 process_called_imports();
411 exit_on_error();
412
413
414 if (warnings>0){
415 fprintf(stdwarn,"Warnings:%i\n",warnings);
416 return 99;
417 }
418 if (cfg_verbose) fprintf(stdwarn,"Success.\n");
419 return 0;
420 } // main()
421