1 /*
2 * bcc.c Version 2001.1
3 * Complete rewrite because the old one was just too confusing!
4 *
5 * There are no significant compile time options (MC6809 and CCC
6 * just change defaults) but you should set LOCALPREFIX.
7 *
8 * Personality flags are:
9 *
10 * -Mn Normal ELKS
11 * -Md MSDOS
12 * -Ms PC Standalone.
13 * -Ml i386 Linux
14 * -M8 CvW's c386
15 * -M9 MC6809 with bcc
16 * -M0 A framework for the -B option.
17 */
18 #include <stdio.h>
19 #ifdef __STDC__
20 #include <limits.h>
21 #include <stdlib.h>
22 #ifndef MSDOS
23 #include <unistd.h>
24 #endif
25 #else
26 #include <malloc.h>
27 #endif
28 #include <string.h>
29 #include <memory.h>
30 #include <fcntl.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #ifndef MSDOS
34 #include <sys/wait.h>
35 #include <signal.h>
36 #endif
37 #include "version.h"
38
39 #ifdef MSDOS
40 #define LOCALPREFIX /linux86
41 #define EXESUF ".exe"
42 #define R_OK 4 /* Test for read permission. */
43 #define W_OK 2 /* Test for write permission. */
44 #define X_OK 1 /* Test for execute permission. */
45 #define F_OK 0 /* Test for existence. */
46 #define DEFARCH 0 /* Default to 8086 code */
47 #include "version.h"
48 #else
49 #define EXESUF
50 #endif
51
52 #define AS "as" EXESUF
53 #define LD "ld" EXESUF
54 #define CPP "cpp" EXESUF
55 #define CC1 "cc1" EXESUF
56 #define OPT "opt" EXESUF
57
58 #define CC1C386 "c386" EXESUF
59
60 #define AS09 "as09" EXESUF
61 #define LD09 "ld09" EXESUF
62
63 #define CPPBCC "bcc-cpp" EXESUF
64 #define CC1BCC "bcc-cc1" EXESUF
65 #define AS86 "as86" EXESUF
66 #define LD86 "ld86" EXESUF
67
68 #define GCC "gcc"
69 #define UNPROTO "unproto" EXESUF
70 #define OPTIM "copt" EXESUF
71
72 #if __STDC__ == 1
73 #define P(x) x
74 #define HASHIT(x) #x
75 #define QUOT(x) HASHIT(x)
76 #else
77 #define P(x) ()
78 /* Well you find something that works! */
79 #define QUOT(x) "x"
80 #endif
81
82 struct command {
83 char * cmd;
84 char * altcmd;
85 char * fullpath;
86 int numargs;
87 int maxargs;
88 char ** arglist;
89 } command = { 0,0,0,0,0,0 };
90
91 struct file_list {
92 struct file_list * next;
93 char * file;
94 char * oldfile;
95 char * name;
96 int filetype; /* Char, notional extention of file. */
97 } * files;
98
99 struct opt_list {
100 struct opt_list * next;
101 char * opt;
102 int opttype; /* Where the option should go */
103 } * options;
104
105 int opt_v, opt_V, opt_e, opt_x, opt_I, opt_L, opt_W, opt_i,
106 opt_O, opt_M, opt_f
107 #ifndef VERY_SMALL_MEMORY
108 , opt_7
109 #endif
110 ;
111
112 #ifdef DEFARCH
113 int opt_arch = (DEFARCH != 0);
114 #else
115 int opt_arch = sizeof (char *) >= 4;
116 #endif
117
118 int do_preproc = 1; /* c -> i */
119 int do_unproto = 0; /* i -> i */
120 int do_compile = 1; /* i -> s */
121 int do_optim = 0; /* s -> s */
122 int do_as = 1; /* s -> o */
123 int do_link = 1; /* o -> done */
124 char * executable_name = 0;
125
126 int file_count = 0;
127 int dyn_count = 0;
128 int error_count = 0;
129 char * progname = "C";
130 #ifdef MSDOS
131 char * tmpdir = "";
132 #else
133 char * tmpdir = "/tmp/";
134 #endif
135
136 int main P((int argc, char **argv));
137
138 void add_prefix P((char * path));
139 void build_prefix P((char * path1, char * path2, char * path3));
140 void run_aspreproc P((struct file_list * file));
141 void run_preproc P((struct file_list * file));
142 void run_unproto P((struct file_list * file));
143 void run_compile P((struct file_list * file));
144 void run_optim P((struct file_list * file));
145 void run_as P((struct file_list * file));
146 void run_link P((void));
147 void command_reset P((void));
148 void command_opt P((char * option));
149 void command_arch P((void));
150 void command_opts P((int opykey));
151 void newfilename P((struct file_list * file, int last_stage, int new_extn, int use_o));
152 void run_unlink P((void));
153 void validate_link_opt P((char * option));
154 void validate_link_opts P((void));
155 void append_file P((char * filename, int ftype));
156 void append_option P((char * option, int otype));
157 void prepend_option P((char * option, int otype));
158 char * build_libpath P((char * opt, char * str, char * suffix));
159 void * xalloc P((int size));
160 void Usage P((void));
161 void fatal P((char * why));
162 char * copystr P((char * str));
163 char * catstr P((char * str, char * str2));
164 void reset_prefix_path P((void));
165 void run_command P((struct file_list * file));
166 void getargs P((int argc, char ** argv));
167
168 char * prefix_path = "";
169
170 #ifdef LOCALPREFIX
171 char * localprefix = QUOT(LOCALPREFIX);
172 #else
173 char * localprefix = "/";
174 #endif
175
176 /* These paths are NATIVE install paths, change others below */
177 char * default_include = "/usr/include";
178 char * optim_rules = "/lib";
179 #ifdef LIBDIR
180 char * default_libdir = QUOT(LIBDIR);
181 #else
182 char * default_libdir = "/lib";
183 #endif
184 char * libdir_suffix = "";
185
186 char devnull[] = "/dev/null";
187 char * exec_prefixs[16] = {
188 0 /* Last chance is contents of $PATH */
189 };
190
191 char * libc = "-lc";
192
193 int
main(argc,argv)194 main(argc, argv)
195 int argc;
196 char ** argv;
197 {
198 struct file_list * next_file;
199 char * temp;
200
201 progname = argv[0];
202 if ((temp = getenv("BCC_PREFIX")) != 0 )
203 localprefix = copystr(temp);
204
205 getargs(argc, argv);
206 validate_link_opts();
207
208 reset_prefix_path();
209
210 if (!*localprefix || !localprefix[1]) {
211
212 if (*localprefix == '/') {
213 /* Paths for full NATIVE install "-M/" */
214 build_prefix(default_libdir, libdir_suffix, "");
215 build_prefix(default_libdir, "", "");
216
217 default_include = build_libpath("-I", "/usr/include", "");
218 default_libdir = build_libpath("-L", default_libdir, libdir_suffix);
219 optim_rules = build_libpath("-d", optim_rules, libdir_suffix);
220 #if 0
221 } else if (*localprefix == '+') {
222 /* Paths for a special */
223 #endif
224 } else {
225 /* Relative paths to a build dir "-M-" */
226 build_prefix("/lib", libdir_suffix, "");
227 build_prefix("/lib", "", "");
228
229 default_include = build_libpath("-I", "/include", "");
230 default_libdir = build_libpath("-L", "/lib", libdir_suffix);
231 optim_rules = build_libpath("-d", "/lib", libdir_suffix);
232 }
233
234 } else {
235 /* Relative paths to normal PREFIX directory */
236 default_include = build_libpath("-I", "/lib/bcc/include", "");
237 default_libdir = build_libpath("-L", "/lib/bcc", libdir_suffix);
238 optim_rules = build_libpath("-d", "/lib/bcc", libdir_suffix);
239
240 build_prefix("/lib/bcc", libdir_suffix, "");
241 build_prefix("/lib/bcc", "", "");
242 }
243
244 build_prefix("/bin", "", "");
245 #ifdef BINDIR
246 add_prefix(QUOT(BINDIR) "/");
247 #endif
248
249 if (opt_v>1) { command.cmd = ""; command_reset(); }
250
251 for(next_file = files; next_file && !error_count; next_file = next_file->next)
252 {
253 if (next_file->filetype == 'o') continue;
254
255 if (opt_V)
256 fprintf(stderr, "%s:\n", next_file->file);
257
258 /* Assembler that's not to be optimised. */
259 if (do_preproc && next_file->filetype == 'x') run_aspreproc(next_file);
260 if (do_preproc && next_file->filetype == 'S') run_aspreproc(next_file);
261 if (do_as && next_file->filetype == 's') run_as(next_file);
262
263 /* C source */
264 if (do_preproc && next_file->filetype == 'c') run_preproc(next_file);
265 if (do_unproto && do_compile && next_file->filetype == 'i')
266 run_unproto(next_file);
267 if (do_compile && next_file->filetype == 'i') run_compile(next_file);
268 if (do_optim && next_file->filetype == 's') run_optim(next_file);
269 if (do_as && next_file->filetype == 's') run_as(next_file);
270 }
271
272 if (do_link && !error_count)
273 run_link();
274
275 run_unlink();
276 exit(error_count>0);
277 }
278
279 char *
copystr(str)280 copystr(str)
281 char * str;
282 {
283 return strcpy(xalloc(strlen(str)+1), str);
284 }
285
286 char *
catstr(str,str2)287 catstr(str, str2)
288 char * str, * str2;
289 {
290 return strcat(strcpy(xalloc(strlen(str)+strlen(str2)+1), str), str2);
291 }
292
293 void
run_aspreproc(file)294 run_aspreproc(file)
295 struct file_list * file;
296 {
297 static char cc1bcc[] = CC1BCC;
298
299 if (opt_arch<5) {
300 if (opt_e)
301 command.cmd = cc1bcc;
302 else {
303 command.cmd = CPPBCC;
304 command.altcmd = cc1bcc;
305 }
306 } else
307 command.cmd = CPP;
308 command_reset();
309 newfilename(file, (!do_as && !do_optim), (do_compile?'s':'i'), (opt_arch<5));
310 if (opt_arch<5 && command.cmd == cc1bcc)
311 command_opt("-E");
312 else if (opt_arch<5 && do_unproto)
313 command_opt("-A");
314 command_opts('p');
315 command_opt("-D__ASSEMBLER__");
316
317 command_arch();
318 run_command(file);
319 }
320
321 void
run_preproc(file)322 run_preproc(file)
323 struct file_list * file;
324 {
325 int last_stage = 0;
326 int combined_cpp;
327 static char cc1bcc[] = CC1BCC;
328
329 if (opt_arch<5) {
330 if (opt_e)
331 command.cmd = cc1bcc;
332 else {
333 command.cmd = CPPBCC;
334 command.altcmd = cc1bcc;
335 }
336 } else
337 command.cmd = CPP;
338 command_reset();
339
340 combined_cpp = (command.cmd == cc1bcc &&
341 opt_arch != 3 &&
342 opt_e < 2 &&
343 !do_unproto &&
344 do_compile);
345
346 if (combined_cpp && !do_optim && !do_as ) last_stage =1;
347 if (!combined_cpp && !do_compile ) last_stage =1;
348
349 newfilename(file, last_stage, (combined_cpp?'s':'i'), (opt_arch<5));
350
351 if (!combined_cpp && opt_arch<5) {
352 if (command.cmd == cc1bcc)
353 command_opt("-E");
354 else if (do_unproto)
355 command_opt("-A");
356 }
357
358 command_opts('p');
359 command_opts('C');
360 if (combined_cpp)
361 {
362 if (opt_arch<5 && !do_as)
363 command_opt("-t");
364 command_opts('c');
365 }
366
367 if (!opt_I)
368 command_opt(default_include);
369
370 command_arch();
371
372 run_command(file);
373 }
374
375 void
run_unproto(file)376 run_unproto(file)
377 struct file_list * file;
378 {
379 command.cmd = UNPROTO;
380 command_reset();
381 newfilename(file, !do_compile, 'i', 0);
382 command_opts('u');
383
384 run_command(file);
385 }
386
387 void
run_compile(file)388 run_compile(file)
389 struct file_list * file;
390 {
391 if (opt_arch == 3) command.cmd = CC1C386;
392 else if (opt_arch<5) command.cmd = CC1BCC;
393 else command.cmd = CC1;
394 command_reset();
395 newfilename(file, !(do_optim || do_as), 's', (opt_arch != 3 && opt_arch<5));
396
397 if (opt_arch<5 && !do_as)
398 command_opt("-t");
399 #ifndef VERY_SMALL_MEMORY
400 if (opt_7)
401 command_opt("-7");
402 #endif
403
404 command_opts('c');
405 command_opts('C');
406
407 command_arch();
408
409 run_command(file);
410 }
411
412 void
run_optim(file)413 run_optim(file)
414 struct file_list * file;
415 {
416 char buf[32];
417 if (opt_arch<5) command.cmd = OPTIM;
418 else command.cmd = OPT;
419 command_reset();
420 newfilename(file, !do_as, 's', 1);
421 command_opt("-c!");
422 if (opt_O && opt_arch == 0)
423 {
424 sprintf(buf, "-huse16 %c86", opt_O);
425 command_opt(buf);
426 }
427 command_opt(optim_rules);
428
429 command_opt("rules.start");
430 command_opts('o');
431
432 if (opt_O) {
433 if (opt_arch == 0)
434 sprintf(buf, "rules.%c86", opt_O);
435 else
436 sprintf(buf, "rules.lv_%c", opt_O);
437 command_opt(buf);
438 }
439
440 switch(opt_arch) {
441 case 0: command_opt("rules.86"); break;
442 case 1:
443 case 2: command_opt("rules.i386"); break;
444 case 4: command_opt("rules.6809"); break;
445 default:command_opt("rules.mid"); break;
446 }
447
448 command_opt("rules.end");
449
450 run_command(file);
451 }
452
453 void
run_as(file)454 run_as(file)
455 struct file_list * file;
456 {
457 char * buf;
458 switch(opt_arch)
459 {
460 case 0: case 1: case 2:
461 command.cmd = AS86; break;
462 case 4: command.cmd = AS09; break;
463 default: command.cmd = AS; break;
464 }
465 command_reset();
466 newfilename(file, (!do_link && opt_arch!=2), 'o', 1);
467 if (opt_arch==3)
468 command_opt("-j");
469 if (opt_arch<5)
470 command_opt("-u");
471 command_opts('a');
472 if (opt_W)
473 command_opt("-w-");
474 else
475 command_opt("-w");
476 command_arch();
477 command_opt("-n");
478 buf = catstr(file->name, ".s");
479 command_opt(buf);
480 free(buf);
481
482 run_command(file);
483
484 if (opt_arch == 2)
485 {
486 command.cmd = LD86;
487 command_reset();
488 command_opt("-r");
489 command_opt("-N");
490 newfilename(file, !do_link, 'o', 1);
491 run_command(file);
492 }
493 }
494
495 void
run_link()496 run_link()
497 {
498 struct file_list * next_file;
499
500 switch(opt_arch)
501 {
502 case 0: case 1:
503 command.cmd = LD86; break;
504 case 2: command.cmd = GCC; break;
505 case 4: command.cmd = LD09; break;
506 default: command.cmd = LD; break;
507 }
508 command_reset();
509 if (executable_name) {
510 command_opt("-o");
511 command_opt(executable_name);
512 }
513
514 if (opt_arch < 2)
515 command_opt("-y");
516
517 command_opts('l');
518 if (opt_arch != 2)
519 {
520 if (opt_arch == 0 && !opt_i)
521 command_opt("-i");
522
523 if (!opt_L)
524 command_opt(default_libdir);
525 command_arch();
526
527 if (!opt_x)
528 command_opt("-C0");
529 }
530 /* Current Debian compilers only work in with this: */
531 else command_opt("--static");
532
533 for(next_file = files; next_file; next_file = next_file->next)
534 command_opt(next_file->file);
535
536 if (opt_arch != 2)
537 command_opt(libc);
538 run_command(0);
539 }
540
541 void
validate_link_opt(option)542 validate_link_opt(option)
543 char * option;
544 {
545 int err = 0;
546 if (option[0] != '-') return;
547
548 switch(option[1]) {
549 default:
550 err = 1;
551 break;
552 case '0': /* use 16-bit libraries */
553 case '3': /* use 32-bit libraries */
554 case 'M': /* print symbols linked */
555 case 'i': /* separate I & D output */
556 case 'm': /* print modules linked */
557 case 's': /* strip symbols */
558 case 't': /* trace modules linked */
559 case 'z': /* unmapped zero page */
560 case 'N': /* Native format a.out */
561 case 'd': /* Make a headerless outfile */
562 case 'c': /* Write header in CP/M-86 format */
563 case 'y': /* Use a newer symbol table */
564 if (option[2] != 0 && option[2] != '-')
565 err = 1;
566 break;
567 case 'C': /* startfile name */
568 case 'L': /* library path */
569 case 'O': /* library file name */
570 case 'T': /* text base address */
571 case 'D': /* data base address */
572 case 'H': /* heap top address */
573 case 'l': /* library name */
574 case 'o': /* output file name */
575 break;
576 }
577 if (err) {
578 if (do_link)
579 fprintf(stderr, "warning: unknown option %s passed to linker.\n",
580 option);
581 else
582 fprintf(stderr, "warning: option %s not recognised.\n", option);
583 } else if (!do_link)
584 fprintf(stderr, "warning: linker option %s unused.\n", option);
585 }
586
587 void
validate_link_opts()588 validate_link_opts()
589 {
590 struct opt_list * ol;
591 struct file_list * next_file;
592 if (opt_arch>1) return; /* Only check ld86 options */
593
594 for(ol=options; ol; ol=ol->next)
595 if (ol->opttype == 'l')
596 validate_link_opt(ol->opt);
597
598 for(next_file = files; next_file; next_file = next_file->next)
599 validate_link_opt(next_file->file);
600
601 if (!do_link) {
602 if (opt_i)
603 fprintf(stderr, "warning: linker option -i unused.\n");
604 if (opt_x)
605 fprintf(stderr, "warning: linker option -x unused.\n");
606 if (opt_L)
607 fprintf(stderr, "warning: linker option -L unused.\n");
608 }
609 }
610
611 void
command_reset()612 command_reset()
613 {
614 #ifndef MAXPATHLEN
615 #define MAXPATHLEN 1024
616 #endif
617 char buf[MAXPATHLEN];
618 char ** prefix;
619 char * saved_cmd;
620
621 if (command.arglist)
622 {
623 int i;
624 for(i=0; i<command.maxargs; i++)
625 if(command.arglist[i])
626 free(command.arglist[i]);
627 free(command.arglist);
628 }
629 command.arglist = 0;
630 command.numargs = 1;
631 command.maxargs = 20;
632
633 command.arglist = xalloc(command.maxargs*sizeof(char**));
634 command.arglist[0] = copystr(command.cmd);
635
636 if (command.fullpath) free(command.fullpath);
637 command.fullpath = 0;
638
639 /* Search for the exe, nb as this will probably be called from 'make'
640 * there's not much point saving this.
641 */
642 saved_cmd = command.cmd;
643 for(;;)
644 {
645 for(prefix=exec_prefixs; *prefix; prefix++)
646 {
647 char * p;
648 if (*prefix == devnull) continue;
649
650 p = strchr(*prefix, '~');
651 if (!p) strcpy(buf, *prefix);
652 else
653 {
654 memcpy(buf, *prefix, p-*prefix);
655 buf[p-*prefix] = 0;
656
657 strcat(buf, prefix_path);
658 strcat(buf, p+1);
659 }
660 strcat(buf, command.cmd);
661
662 if (!*command.cmd)
663 fprintf(stderr, "PATH%d=%s\n", prefix-exec_prefixs, buf);
664 else if (access(buf, X_OK) == 0)
665 {
666 command.fullpath = copystr(buf);
667 break;
668 }
669 }
670 if (command.fullpath || !command.altcmd) break;
671 command.cmd = command.altcmd;
672 command.altcmd = 0;
673 }
674
675 if (!command.fullpath) {
676 command.cmd = saved_cmd;
677 command.fullpath = copystr(command.cmd);
678 }
679 command.altcmd = 0;
680 }
681
682 void
command_opt(option)683 command_opt(option)
684 char * option;
685 {
686 if (command.maxargs <= command.numargs+1) {
687 char ** newbuf = xalloc(command.maxargs*2*sizeof(char**));
688 memcpy(newbuf, command.arglist, command.maxargs*sizeof(char**));
689 command.maxargs *= 2;
690 free(command.arglist);
691 command.arglist = newbuf;
692 }
693
694 command.arglist[command.numargs++] = copystr(option);
695 }
696
697 void
command_arch()698 command_arch()
699 {
700 if (opt_arch==0) command_opt("-0");
701 if (opt_arch==1) command_opt("-3");
702 if (opt_arch==2) command_opt("-3");
703 }
704
705 void
command_opts(optkey)706 command_opts(optkey)
707 int optkey;
708 {
709 struct opt_list * ol;
710 for(ol=options; ol; ol=ol->next)
711 if (ol->opttype == optkey)
712 command_opt(ol->opt);
713 }
714
newfilename(file,last_stage,new_extn,use_o)715 void newfilename(file, last_stage, new_extn, use_o)
716 struct file_list * file;
717 int last_stage;
718 int new_extn;
719 int use_o;
720 {
721 file->filetype = new_extn;
722 if (file->oldfile) free(file->oldfile);
723 file->oldfile = file->file;
724 file->file = 0;
725
726 if (last_stage) {
727 if (executable_name)
728 file->file = copystr(executable_name);
729 else
730 {
731 char buf[4];
732 buf[0] = '.';
733 buf[1] = file->filetype;
734 buf[2] = 0;
735 file->file = catstr(file->name, buf);
736 }
737 }
738 else
739 {
740 char buf[16];
741 #ifdef MSDOS
742 sprintf(buf, "$$%05d$", dyn_count++);
743 #else
744 sprintf(buf, "$$%04d%05d", dyn_count++, getpid());
745 #endif
746 file->file = catstr(tmpdir, buf);
747 }
748
749 command_opt(file->oldfile);
750 /* *.i files go to the stdout */
751 if (last_stage && file->filetype == 'i') return;
752 if (use_o) command_opt("-o");
753 command_opt(file->file);
754 }
755
756 void
run_unlink()757 run_unlink()
758 {
759 int i;
760 for(i=0; i<dyn_count; i++)
761 {
762 char buf[16];
763 char * p;
764 #ifdef MSDOS
765 sprintf(buf, "$$%05d$", i);
766 #else
767 sprintf(buf, "$$%04d%05d", i, getpid());
768 #endif
769 p = catstr(tmpdir, buf);
770 if (opt_v>1)
771 fprintf(stderr, "rm %s\n", p);
772 if (opt_v>2)
773 continue;
774 if (unlink(p) < 0)
775 {
776 if (error_count==0 || opt_v>1)
777 fprintf(stderr, "Error unlinking %s\n", p);
778 error_count++;
779 }
780 free(p);
781 }
782 }
783
784 void
getargs(argc,argv)785 getargs(argc, argv)
786 int argc;
787 char ** argv;
788 {
789 int ar;
790 char * pflag = 0;
791 int control_count = 0;
792 int exe_count = 0;
793
794 for(ar=1; ar<argc; ) if (argv[ar][0] != '-')
795 {
796 #ifdef __CYGWIN__
797 if ( executable_name == 0 ) {
798 char * p = strrchr(argv[ar], '.');
799 if (p && p == argv[ar] + strlen(argv[ar]) - 2)
800 {
801 /* This will actually create a COM file, but windows doesn't
802 * care and cygwin will only do PATH searches for EXE files.
803 */
804 *p=0;
805 executable_name = catstr(argv[ar], ".exe");
806 *p = '.';
807 }
808 }
809 #endif
810 append_file(argv[ar++], 0);
811 file_count++;
812 }
813 else
814 {
815 int opt;
816 int used_arg = 1, inc_ar=0;
817 char * opt_arg;
818
819 if (argv[ar][2]) opt_arg = argv[ar]+2;
820 else
821 {
822 inc_ar++;
823 if (argv[ar+1]) opt_arg = argv[ar+1];
824 else
825 {
826 inc_ar++;
827 opt_arg = "ERROR";
828 }
829 }
830 /* Special case -? is different from -?abcdef */
831 if(!pflag && argv[ar][2] == 0) switch(argv[ar][1])
832 {
833 case 'a': case 'L': case 'I': case 'M': case 'O': case 'P': case 'Q':
834 pflag = argv[ar]+1;
835 used_arg = 0;
836 break;
837 }
838 /* Options that need an argument */
839 if(!pflag) switch(argv[ar][1])
840 {
841 case 'a':
842 if(strcmp(argv[ar], "-ansi") == 0) {
843 do_unproto = 1;
844 #if 0
845 /* NOTE I'm setting this to zero, this isn't a _real_ Ansi cpp. */
846 prepend_option("-D__STDC__=0", 'p');
847 #else
848 prepend_option("-D__STDC__", 'p');
849 #endif
850 }
851 else
852 Usage();
853 break;
854
855 case 't':
856 append_option("-t", 'a');
857 /*FALLTHROUGH*/
858 case 'A':
859 append_option(opt_arg, 'a');
860 break;
861 case 'C':
862 append_option(opt_arg, 'c');
863 break;
864 case 'P':
865 append_option(opt_arg, 'p');
866 break;
867 case 'X':
868 append_option(opt_arg, 'l');
869 break;
870 case 'u':
871 append_option(opt_arg, 'u');
872 break;
873
874 case 'L':
875 append_option(argv[ar], 'l');
876 break;
877
878 case 'Q':
879 append_option(argv[ar], 'c');
880 break;
881
882 case 'O':
883 do_optim=1;
884 if (!opt_arg[1] && ( opt_arg[0] >= '1' && opt_arg[0] <= '9' ))
885 opt_O = opt_arg[0];
886 else if (opt_arg[0] == '-')
887 append_option(opt_arg, 'o');
888 else
889 {
890 char * p = xalloc(strlen(opt_arg)+8);
891 strcpy(p, "rules.");
892 strcat(p, opt_arg);
893 append_option(p, 'o');
894 free(p);
895 }
896 break;
897
898 case 'o':
899 exe_count++;
900 executable_name = opt_arg;
901 break;
902
903 case 'B':
904 add_prefix(opt_arg);
905 break;
906
907 case 'I':
908 case 'D':
909 case 'U':
910 append_option(argv[ar], 'p');
911 break;
912
913 case 'T':
914 tmpdir = catstr(opt_arg, "/");
915 break;
916
917 case 'M':
918 if (opt_arg[0] == '/') {
919 localprefix = copystr(opt_arg);
920 break;
921 }
922 if (opt_arg[1]) Usage();
923 if (opt_arg[0] == '-') {
924 localprefix = "";
925 break;
926 }
927 opt_M = *opt_arg;
928 break;
929
930 default:
931 pflag = argv[ar]+1;
932 used_arg = 0;
933 break;
934 }
935 /* Singleton flags */
936 if(pflag) switch(opt = *pflag++)
937 {
938 case 'P':
939 append_option("-P", 'p');
940 /*FALLTHROUGH*/
941 case 'E':
942 control_count++;
943 do_compile = do_link = do_as = 0;
944 break;
945 case 'S':
946 control_count++;
947 do_as = do_link = 0;
948 break;
949 case 'c':
950 control_count++;
951 do_link = 0;
952 break;
953 case 'O':
954 do_optim=1;
955 break;
956
957 case 'G': opt_M = 'g'; break;
958
959 case 'v': opt_v++; break;
960 case 'V': opt_V++; break;
961 case 'e': opt_e++; break;
962 case 'x': opt_x++; break;
963 case 'I': opt_I++; break;
964 case 'L': opt_L++; break;
965 case 'i': opt_i++; break;
966 case 'f': opt_f++; break;
967 #ifndef VERY_SMALL_MEMORY
968 case '7': opt_7++; break;
969 #endif
970
971 case 'W': opt_W++; break;
972
973 case '0': opt_arch=0; break;
974 case '3': opt_arch=1; break;
975
976 case 'w': /*IGNORED*/ break;
977 case 'g': /*IGNORED*/ break;
978 case 'p': /*IGNORED*/ break;
979
980 default:
981 if (pflag == argv[ar]+2) {
982 /* Special; unknown options saved as flags for the linker */
983 append_file(argv[ar], 'o');
984 pflag = 0;
985 }
986 else
987 Usage();
988 }
989 if (!pflag || !*pflag) { ar++; pflag = 0; }
990 if (used_arg && inc_ar) ar++;
991 if (used_arg && inc_ar==2)
992 fatal("Last option requires an argument");
993 }
994
995 if (control_count>1)
996 fatal("only one option from -E -P -S -c allowed");
997 if (exe_count>1)
998 fatal("only one -o option allowed");
999
1000 if (file_count==0) Usage();
1001
1002 if (exe_count && file_count != 1 && !do_link)
1003 fatal("only one input file for each non-linked output");
1004
1005 add_prefix(getenv("BCC_EXEC_PREFIX"));
1006
1007 #ifdef MC6809
1008 if (opt_M==0) opt_M = '9';
1009 #endif
1010 #ifdef CCC
1011 if (opt_M==0) opt_M = '8';
1012 #endif
1013 #ifdef MSDOS
1014 if (opt_M==0) opt_M = 'd';
1015 #endif
1016 #ifdef __CYGWIN__
1017 if (opt_M==0) opt_M = 'd';
1018 #endif
1019 if (opt_M==0) opt_M = (opt_arch==1 ?'l':'n');
1020 switch(opt_M)
1021 {
1022 case 'n': /* Normal Elks */
1023 prepend_option("-D__unix__", 'p');
1024 prepend_option("-D__ELKS__", 'p');
1025 libc="-lc";
1026 break;
1027 case 'f': /* Fast Call Elks */
1028 prepend_option("-D__unix__", 'p');
1029 prepend_option("-D__ELKS__", 'p');
1030 append_option("-c", 'C');
1031 append_option("-f", 'C');
1032 libc="-lc_f";
1033 break;
1034 case 'c': /* Caller saves Elks */
1035 prepend_option("-D__unix__", 'p');
1036 prepend_option("-D__ELKS__", 'p');
1037 append_option("-c", 'C');
1038 libc="-lc";
1039 break;
1040 case 's': /* Standalone 8086 */
1041 prepend_option("-D__STANDALONE__", 'p');
1042 libc="-lc_s";
1043 break;
1044 case 'd': /* DOS COM file */
1045 prepend_option("-D__MSDOS__", 'p');
1046 if (do_link) {
1047 libc="-ldos";
1048 append_option("-d", 'l');
1049 append_option("-T100", 'l');
1050 }
1051 break;
1052 case 'l': /* 386 Linux a.out */
1053 opt_arch=1;
1054 prepend_option("-D__unix__", 'p');
1055 prepend_option("-D__linux__", 'p');
1056 if (do_link) {
1057 libc="-lc";
1058 append_option("-N", 'l');
1059 }
1060 break;
1061 case 'g': /* 386 Linux object using gcc as linker */
1062 opt_arch = 2;
1063 prepend_option("-D__unix__", 'p');
1064 prepend_option("-D__linux__", 'p');
1065
1066 /* This is a more traditional libc, it also gives a 20k executable
1067 * for hello world vs. 400k with glibc2 and --static.
1068 * NB: DLL libc no longer seems to work.
1069 */
1070 add_prefix("/usr/bin/i386-uclibc-");
1071 break;
1072 case '8': /* Use 'c386' program as compiler */
1073 opt_arch = 3;
1074 prepend_option("-D__unix__", 'p');
1075 prepend_option("-D__c386__", 'p');
1076 break;
1077 case '9': /* 6809 compiler */
1078 opt_arch = 4;
1079 prepend_option("-D__6809__", 'p');
1080 break;
1081 case '0': /* Plain old Unix V7 style */
1082 opt_arch = 5;
1083 opt_I = 1;
1084 opt_L = 1;
1085 opt_x = 1;
1086 append_option("/lib/crt0.o", 'l');
1087 break;
1088 default:
1089 fatal("Unknown model specifier for -M valid are: n,f,c,s,d,l,g,8,9,0");
1090 }
1091
1092 if (do_optim)
1093 {
1094 append_option("-O", 'C');
1095 append_option("-O", 'a');
1096 }
1097
1098 if (opt_arch == 0) {
1099 if (opt_f) {
1100 /* append_option("--enable-floats", 'c'); */
1101 libc = catstr(libc, "+f");
1102 } else
1103 append_option("-D__HAS_NO_FLOATS__", 'p');
1104 }
1105
1106 if (opt_arch == 1) libdir_suffix = "/i386";
1107 if (opt_arch == 4) libdir_suffix = "/m09";
1108
1109 #ifdef VERSION
1110 {
1111 char verbuf[64];
1112 sprintf(verbuf, "-D__BCC_VERSION__=0x%02x%02x%02xL",
1113 VER_MAJ, VER_MIN, VER_PAT);
1114 append_option(verbuf, 'p');
1115 }
1116 #endif
1117 }
1118
1119 void
build_prefix(path1,path2,path3)1120 build_prefix(path1, path2, path3)
1121 char * path1, * path2, * path3;
1122 {
1123 char * newstr;
1124 int l;
1125 newstr = xalloc(strlen(path1)+strlen(path2)+strlen(path3)
1126 + strlen(prefix_path)+2);
1127
1128 strcpy(newstr, prefix_path);
1129 strcat(newstr, path1);
1130 strcat(newstr, path2);
1131 strcat(newstr, path3);
1132 l = strlen(newstr);
1133 if (l>1 && newstr[l-1] != '/')
1134 strcat(newstr, "/");
1135
1136 add_prefix(newstr);
1137 }
1138
1139 void
add_prefix(path)1140 add_prefix(path)
1141 char * path;
1142 {
1143 char ** p;
1144 if (!path || !*path) return;
1145
1146 for( p=exec_prefixs;
1147 p<exec_prefixs+(sizeof(exec_prefixs)/sizeof(*p))-1;
1148 p++) {
1149
1150 if( !*p )
1151 {
1152 *p = path;
1153 return;
1154 }
1155 if (strcmp(*p, path) == 0) return;
1156 }
1157 fatal("Too many -B options");
1158 }
1159
append_file(filename,ftype)1160 void append_file (filename, ftype)
1161 char * filename;
1162 int ftype;
1163 {
1164 struct file_list * newfile = xalloc(sizeof(struct file_list));
1165 char * s;
1166 char * name;
1167
1168 newfile->file = copystr(filename);
1169 name = copystr(filename);
1170
1171 s = strrchr(name, '.');
1172
1173 if (ftype)
1174 {
1175 newfile->name = copystr(name);
1176 newfile->filetype = ftype;
1177 }
1178 else if (s && s == name + strlen(name) - 2) {
1179 newfile->filetype = s[1];
1180 *s = 0;
1181 newfile->name = copystr(name);
1182 }
1183 else
1184 newfile->name = copystr(name);
1185 free(name);
1186
1187 if (newfile->filetype == 0) newfile->filetype = 'o'; /* Objects */
1188
1189 if (files==0)
1190 files = newfile;
1191 else
1192 {
1193 struct file_list * fptr;
1194 for(fptr=files; fptr->next; fptr=fptr->next);
1195 fptr->next = newfile;
1196 }
1197 }
1198
1199 void
append_option(option,otype)1200 append_option (option, otype)
1201 char * option;
1202 int otype;
1203 {
1204 struct opt_list * newopt = xalloc(sizeof(struct opt_list));
1205
1206 newopt->opt = copystr(option);
1207 newopt->opttype = otype;
1208
1209 if (options==0)
1210 options = newopt;
1211 else
1212 {
1213 struct opt_list * optr;
1214 for(optr=options; optr->next; optr=optr->next);
1215 optr->next = newopt;
1216 }
1217 }
1218
1219 void
prepend_option(option,otype)1220 prepend_option (option, otype)
1221 char * option;
1222 int otype;
1223 {
1224 struct opt_list * newopt = xalloc(sizeof(struct opt_list));
1225
1226 newopt->opt = copystr(option);
1227 newopt->opttype = otype;
1228
1229 newopt->next = options;
1230 options = newopt;
1231 }
1232
build_libpath(opt,str,suffix)1233 char * build_libpath(opt, str, suffix)
1234 char * opt, * str, * suffix;
1235 {
1236 char * newstr;
1237 newstr = xalloc(strlen(opt)+strlen(str)+strlen(prefix_path)+strlen(suffix)+1);
1238 strcpy(newstr, opt);
1239 strcat(newstr, prefix_path);
1240 strcat(newstr, str);
1241 strcat(newstr, suffix);
1242 return newstr;
1243 }
1244
1245 void *
xalloc(size)1246 xalloc (size)
1247 int size;
1248 {
1249 void * p = malloc(size);
1250 if (!p) fatal("Out of memory");
1251 memset(p, '\0', size);
1252 return p;
1253 }
1254
Usage()1255 void Usage()
1256 {
1257 #ifdef VERSION
1258 #ifdef __AS386_16__
1259 if (opt_v)
1260 fprintf(stderr, "%s: version %s (16bit)\n", progname, VERSION);
1261 #else
1262 if (opt_v)
1263 fprintf(stderr, "%s: version %s\n", progname, VERSION);
1264 #endif
1265 #endif
1266 fprintf(stderr,
1267 "Usage: %s [-ansi] [-options] [-o output] file [files].\n", progname);
1268 exit(1);
1269 }
1270
fatal(str)1271 void fatal(str)
1272 char * str;
1273 {
1274 fprintf(stderr, "%s: Fatal error: %s.\n", progname, str);
1275 exit(1);
1276 }
1277
1278 #ifdef MSDOS
reset_prefix_path()1279 void reset_prefix_path()
1280 {
1281 char *ptr, *temp;
1282
1283 if (*localprefix && localprefix[1]) {
1284 prefix_path = localprefix;
1285 return;
1286 }
1287
1288 temp = copystr(progname);
1289 if( (ptr = strrchr(temp, '\\')) != 0
1290 && temp<ptr-4 && strncmp(ptr-4, "\\BIN", 4) == 0 )
1291 {
1292 ptr[-4] = 0;
1293 prefix_path = temp;
1294 }
1295 else
1296 free(temp);
1297 }
1298 #else
1299
reset_prefix_path()1300 void reset_prefix_path()
1301 {
1302 char *ptr, *temp;
1303
1304 if (*localprefix && localprefix[1]) {
1305 prefix_path = localprefix;
1306 return;
1307 }
1308
1309 if ( *localprefix == '/' && !localprefix[1]) {
1310 prefix_path = "";
1311 return;
1312 }
1313
1314 if( *progname == '/' )
1315 temp = copystr(progname);
1316 else
1317 {
1318 char * s, * d;
1319 ptr = getenv("PATH");
1320 if( ptr==0 || *ptr == 0 ) return;
1321 ptr = copystr(ptr);
1322 temp = copystr("");
1323
1324 for(d=s=ptr; d && *s; s=d)
1325 {
1326 #ifndef __BCC__
1327 #ifdef PATH_MAX
1328 char buf[PATH_MAX];
1329 #else
1330 #ifdef MAXPATHLEN
1331 char buf[MAXPATHLEN];
1332 #else
1333 char buf[1024];
1334 #endif
1335 #endif
1336 #endif
1337
1338 free(temp);
1339 d=strchr(s, ':');
1340 if( d ) *d='\0';
1341 temp = xalloc(strlen(progname)+strlen(s)+2);
1342 strcpy(temp, s);
1343 strcat(temp, "/");
1344 strcat(temp, progname);
1345 #ifndef __BCC__
1346 if( realpath(temp, buf) != 0 )
1347 {
1348 free(temp);
1349 temp = copystr(buf);
1350 }
1351 #endif
1352 if( access(temp, X_OK) == 0 ) break;
1353 d++;
1354 }
1355 if( s == 0 )
1356 {
1357 free(temp);
1358 temp = copystr(progname);
1359 }
1360 free(ptr);
1361 }
1362
1363 if( (ptr = strrchr(temp, '/')) != 0
1364 && temp<ptr-4 && strncmp(ptr-4, "/bin", 4) == 0 )
1365 {
1366 ptr[-4] = 0;
1367 prefix_path = temp;
1368 }
1369 else
1370 free(temp);
1371 }
1372 #endif
1373
1374 void
run_command(file)1375 run_command(file)
1376 struct file_list * file;
1377 {
1378 #ifdef __BCC__
1379 static char ** minienviron[] = {
1380 "PATH=/bin:/usr/bin",
1381 "SHELL=/bin/sh",
1382 0
1383 };
1384 #endif
1385 int i, status;
1386 #ifndef MSDOS
1387 void *oqsig, *oisig, *otsig, *ocsig;
1388 #endif
1389
1390
1391 if (opt_v)
1392 {
1393 fprintf(stderr, "%s", command.fullpath);
1394 for(i=1; command.arglist[i]; i++)
1395 fprintf(stderr, " %s", command.arglist[i]);
1396 fprintf(stderr, "\n");
1397 if (opt_v>2) return;
1398 }
1399
1400 #ifdef MSDOS
1401 status = spawnv(0, command.fullpath, command.arglist);
1402 if (status<0)
1403 {
1404 fprintf(stderr, "Unable to execute %s\n", command.fullpath);
1405 }
1406 #else
1407 oqsig = signal(SIGQUIT, SIG_IGN);
1408 oisig = signal(SIGINT, SIG_IGN);
1409 otsig = signal(SIGTERM, SIG_IGN);
1410 ocsig = signal(SIGCHLD, SIG_DFL);
1411
1412 switch(fork())
1413 {
1414 case -1:
1415 fatal("Forking failure");
1416 case 0:
1417 (void) signal(SIGQUIT, SIG_DFL);
1418 (void) signal(SIGINT, SIG_DFL);
1419 (void) signal(SIGTERM, SIG_DFL);
1420 (void) signal(SIGCHLD, SIG_DFL);
1421
1422 #ifdef __BCC__
1423 execve(command.fullpath, command.arglist, minienviron);
1424 #else
1425 if (command.fullpath[0] =='/')
1426 execv(command.fullpath, command.arglist);
1427 else
1428 execvp(command.fullpath, command.arglist);
1429 #endif
1430 fprintf(stderr, "Unable to execute %s.\n", command.fullpath);
1431 exit(1);
1432 default:
1433 wait(&status);
1434 if (status&0xFF)
1435 {
1436 fprintf(stderr, "%s: killed by signal %d\n",
1437 command.fullpath, (status&0xFF));
1438 }
1439 }
1440
1441 (void) signal(SIGQUIT, oqsig);
1442 (void) signal(SIGINT, oisig);
1443 (void) signal(SIGTERM, otsig);
1444 (void) signal(SIGCHLD, ocsig);
1445 #endif
1446 if (status)
1447 {
1448 if (file) file->filetype = '~';
1449 error_count++;
1450 }
1451 }
1452
1453