Pristine Ack-5.5
[Ack-5.5.git] / fast / driver / driver.c
1 /*      fcc/fm2/fpc 
2         Driver for fast ACK compilers.
3
4         Derived from the C compiler driver from Minix.
5
6         Compile this file with
7                 cc -O -I<ACK home directory>/config -DF?? driver.c
8         where F?? is either FCC, FPC, or FM2.
9         Install the resulting binaries in the EM bin directory.
10         Suggested names: afcc, afm2, and afpc.
11 */
12
13 #if FM2+FPC+FCC > 1
14 Something wrong here! Only one of FM2, FPC, or FCC must be defined
15 #endif
16
17 #ifdef sun3
18 #define MACHNAME        "m68020"
19 #define SYSNAME         "sun3"
20 #endif
21
22 #ifdef vax4
23 #define MACHNAME        "vax4"
24 #define SYSNAME         "vax4"
25 #endif
26
27 #ifdef i386
28 #define MACHNAME        "i386"
29 #define SYSNAME         "i386"
30 #endif
31
32 #include <errno.h>
33 #include <signal.h>
34 #include <stdio.h>
35 #include <em_path.h>
36 #if __STDC__
37 #include <stdarg.h>
38 #else
39 #include <varargs.h>
40 #endif
41
42 /*
43         Version producing ACK .o files in one pass.
44 */
45 #define MAXARGC 256     /* maximum number of arguments allowed in a list */
46 #define USTR_SIZE       128     /* maximum length of string variable */
47
48 typedef char USTRING[USTR_SIZE];
49
50 struct arglist {
51         int al_argc;
52         char *al_argv[MAXARGC];
53 };
54
55 #define CPP_NAME        "$H/lib.bin/cpp"
56 #define LD_NAME         "$H/lib.bin/em_led"
57 #define CV_NAME         "$H/lib.bin/$S/cv"
58 #define SHELL           "/bin/sh"
59
60 char    *CPP;
61 char    *COMP;
62 char    *cc = "cc";
63
64 int kids =  -1;
65 int ecount = 0;
66
67 struct arglist CPP_FLAGS = {
68 #ifdef FCC
69         7,
70 #else
71         13,
72 #endif
73         {
74                 "-D__unix",
75                 "-D_EM_WSIZE=4",
76                 "-D_EM_PSIZE=4",
77                 "-D_EM_SSIZE=2",
78                 "-D_EM_LSIZE=4",
79                 "-D_EM_FSIZE=4",
80                 "-D_EM_DSIZE=8",
81 #ifndef FCC
82                 "-DEM_WSIZE=4",
83                 "-DEM_PSIZE=4",
84                 "-DEM_SSIZE=2",
85                 "-DEM_LSIZE=4",
86                 "-DEM_FSIZE=4",
87                 "-DEM_DSIZE=8",
88 #endif
89         }
90 };
91
92 struct arglist LD_HEAD = {
93         2,
94         {
95                 "$H/lib/$S/head_em",
96 #ifdef FCC
97                 "$H/lib/$S/head_$A"
98 #endif
99 #ifdef FM2
100                 "$H/lib/$S/head_m2"
101 #endif
102 #ifdef FPC
103                 "$H/lib/$S/head_pc"
104 #endif
105         }
106 };
107
108 struct arglist LD_TAIL = {
109 #if defined(sun3) || defined(i386)
110         5,
111 #else
112         4,
113 #endif
114         {
115 #ifdef FCC
116                 "$H/lib/$S/tail_$A",
117 #endif
118 #ifdef FM2
119                 "$H/lib/$S/tail_m2",
120 #endif
121 #ifdef FPC
122                 "$H/lib/$S/tail_pc",
123 #endif
124 #if defined(sun3) || defined(i386)
125                 "$H/lib/$M/tail_fp",
126 #endif
127                 "$H/lib/$M/tail_em",
128                 "$H/lib/$S/tail_mon",
129                 "$H/lib/$M/end_em"
130         }
131 };
132
133 struct arglist align = {
134         5, {
135 #ifdef sun3
136                 "-a0:4",
137                 "-a1:4",
138                 "-a2:0x20000",
139                 "-a3:4",
140                 "-b0:0x2020"
141 #endif
142 #ifdef vax4
143                 "-a0:4",
144                 "-a1:4",
145                 "-a2:0x400",
146                 "-a3:4",
147                 "-b0:0"
148 #endif
149 #ifdef i386
150                 "-a0:4",
151                 "-a1:4",
152                 "-a2:4",
153                 "-a3:4",
154                 "-b1:0x1880000"
155 #endif
156         }
157 };
158
159 struct arglist COMP_FLAGS;
160
161 char *o_FILE = "a.out"; /* default name for executable file */
162
163 #define remove(str)     ((noexec || unlink(str)), (str)[0] = '\0')
164 #define cleanup(str)            (str && str[0] && remove(str))
165 #define init(al)                ((al)->al_argc = 1)
166
167 char ProgCall[128];
168
169 struct arglist SRCFILES;
170 struct arglist LDFILES;
171
172 int RET_CODE = 0;
173
174 struct arglist LD_FLAGS;
175
176 struct arglist CALL_VEC;
177
178 int o_flag = 0;
179 int c_flag = 0;
180 int g_flag = 0;
181 int v_flag = 0;
182 int O_flag = 0;
183 int ansi_c = 0;
184
185 #if __STDC__
186 char *mkstr(char *, ...);
187 #else
188 char *mkstr();
189 #endif
190 char *malloc();
191 char *alloc();
192 char *extension();
193 char *expand_string();
194
195 USTRING ofile;
196 USTRING BASE;
197 USTRING tmp_file;
198
199 int noexec = 0;
200
201 extern char *strcat(), *strcpy(), *mktemp(), *strchr();
202
203 trapcc(sig)
204         int sig;
205 {
206         signal(sig, SIG_IGN);
207         if (kids != -1) kill(kids, sig);
208         cleanup(ofile);
209         cleanup(tmp_file);
210         exit(1);
211 }
212
213 #ifdef FCC
214 #define lang_suffix()   "c"
215 #define comp_name()     "$H/lib.bin/c_ce"
216 #define ansi_c_name()   "$H/lib.bin/c_ce.ansi"
217 #endif /* FCC */
218
219 #ifdef FM2
220 #define lang_suffix()   "mod"
221 #define comp_name()     "$H/lib.bin/m2_ce"
222 #endif /* FM2 */
223
224 #ifdef FPC
225 #define lang_suffix()   "p"
226 #define comp_name()     "$H/lib.bin/pc_ce"
227 #endif /* FPC */
228
229
230 #ifdef FCC
231 int
232 lang_opt(str)
233         char *str;
234 {
235         switch(str[1]) {
236         case 'R':
237                 if (! ansi_c) {
238                         append(&COMP_FLAGS, str);
239                         return 1;
240                 }
241                 break;
242         case '-':       /* debug options */
243                 append(&COMP_FLAGS, str);
244                 return 1;
245         case 'a':       /* -ansi flag */
246                 if (! strcmp(str, "-ansi")) {
247                         ansi_c = 1;
248                         COMP = expand_string(ansi_c_name());
249                         return 1;
250                 }
251                 break;
252         case 'w':       /* disable warnings */
253                 if (! ansi_c) {
254                         append(&COMP_FLAGS, str);
255                         return 1;
256                 }
257                 if (str[2]) {
258                         str[1] = '-';
259                         append(&COMP_FLAGS, &str[1]);
260                 }
261                 else append(&COMP_FLAGS, "-a");
262                 return 1;
263         }
264         return 0;
265 }
266 #endif /* FCC */
267
268 #ifdef FM2
269 int
270 lang_opt(str)
271         char *str;
272 {
273         switch(str[1]) {
274         case '-':       /* debug options */
275         case 'w':       /* disable warnings */
276         case 'R':       /* no runtime checks */
277         case 'W':       /* add warnings */
278         case 'L':       /* no line numbers */
279         case 'A':       /* extra array bound checks */
280         case '3':       /* only accept 3rd edition Modula-2 */
281                 append(&COMP_FLAGS, str);
282                 return 1;
283         case 'I':
284                 append(&COMP_FLAGS, str);
285                 break;  /* !!! */
286         case 'U':       /* underscores in identifiers allowed */
287                 if (str[2] == '\0') {
288                         append(&COMP_FLAGS, str);
289                         return 1;
290                 }
291                 break;
292         case 'e':       /* local extension for Modula-2 compiler:
293                            procedure constants
294                         */
295                 str[1] = 'l';
296                 append(&COMP_FLAGS, str);
297                 return 1;
298         }
299         return 0;
300 }
301 #endif /* FM2 */
302
303 #ifdef FPC
304 int
305 lang_opt(str)
306         char *str;
307 {
308         switch(str[1]) {
309         case '-':       /* debug options */
310         case 'a':       /* enable assertions */
311         case 'd':       /* allow doubles (longs) */
312         case 'i':       /* set size of integer sets */
313         case 't':       /* tracing */
314         case 'w':       /* disable warnings */
315         case 'A':       /* extra array bound checks */
316         case 'C':       /* distinguish between lower case and upper case */
317         case 'L':       /* no FIL and LIN instructions */
318         case 'R':       /* no runtime checks */
319                 append(&COMP_FLAGS, str);
320                 return 1;
321         case 'u':
322         case 'U':
323                 /* underscores in identifiers */
324         case 's':
325                 /* only compile standard pascal */
326         case 'c':
327                 /* C type strings */
328                 if (str[2] == '+' && str[3] == '\0') {
329                         str[2] = 0;
330                         append(&COMP_FLAGS, str);
331                         return 1;
332                 }
333         }
334         return 0;
335 }
336 #endif /* FPC */
337
338 main(argc, argv)
339         char *argv[];
340 {
341         char *str;
342         char **argvec;
343         int count;
344         char *ext;
345         register struct arglist *call = &CALL_VEC;
346         char *file;
347         char *ldfile;
348         char *INCLUDE = 0;
349         int compile_cnt = 0;
350
351         setbuf(stdout, (char *) 0);
352         basename(*argv++,ProgCall);
353
354         COMP = expand_string(comp_name());
355         CPP = expand_string(CPP_NAME);
356
357 #ifdef vax4
358         append(&CPP_FLAGS, "-D__vax");
359 #endif
360 #ifdef sun3
361         append(&CPP_FLAGS, "-D__sun");
362 #endif
363 #ifdef m68020
364         append(&CPP_FLAGS, "-D__mc68020");
365         append(&CPP_FLAGS, "-D__mc68000");
366 #endif
367
368         if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
369                 signal(SIGHUP, trapcc);
370         if (signal(SIGINT, SIG_IGN) != SIG_IGN)
371                 signal(SIGINT, trapcc);
372         if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
373                 signal(SIGQUIT, trapcc);
374         while (--argc > 0) {
375                 if (*(str = *argv++) != '-') {
376                         append(&SRCFILES, str);
377                         continue;
378                 }
379
380                 if (lang_opt(str)) {
381                 }
382                 else switch (str[1]) {
383
384                 case 'c':       /* stop after producing .o files */
385                         c_flag = 1;
386                         break;
387                 case 'D':       /* preprocessor #define */
388                 case 'U':       /* preprocessor #undef */
389                         append(&CPP_FLAGS, str);
390                         break;
391                 case 'I':       /* include directory */
392                         append(&CPP_FLAGS, str);
393                         break;
394                 case 'g':       /* debugger support */
395                         append(&COMP_FLAGS, str);
396                         g_flag = 1;
397                         break;
398                 case 'a':       /* -ansi flag */
399                         if (! strcmp(str, "-ansi")) {
400                                 ansi_c = 1;
401                                 return 1;
402                         }
403                         break;
404                 case 'o':       /* target file */
405                         if (argc-- >= 0) {
406                                 o_flag = 1;
407                                 o_FILE = *argv++;
408                                 ext = extension(o_FILE);
409                                 if (ext != o_FILE && ! strcmp(ext, lang_suffix())
410                                 ) {
411                                         error("-o would overwrite %s", o_FILE);
412                                 }
413                         }
414                         break;
415                 case 'u':       /* mark identifier as undefined */
416                         append(&LD_FLAGS, str);
417                         if (argc-- >= 0)
418                                 append(&LD_FLAGS, *argv++);
419                         break;
420                 case 'O':       /* use built in peephole optimizer */
421                         O_flag = 1;
422                         break;
423                 case 'v':       /* verbose */
424                         v_flag++;
425                         if (str[2] == 'n')
426                                 noexec = 1;
427                         break;
428                 case 'l':       /* library file */
429                         append(&SRCFILES, str);
430                         break;
431                 case 'M':       /* use other compiler (for testing) */
432                         strcpy(COMP, str+2);
433                         break;
434                 case 's':       /* strip */
435                         if (str[2] == '\0') {
436                                 append(&LD_FLAGS, str);
437                                 break;
438                         }
439                         /* fall through */
440                 default:
441                         warning("%s flag ignored", str);
442                         break;
443                 }
444         }
445
446         if (ecount) exit(1);
447
448         count = SRCFILES.al_argc;
449         argvec = &(SRCFILES.al_argv[0]);
450         while (count-- > 0) {
451                 ext = extension(*argvec);
452                 if (*argvec[0] != '-' && 
453                     ext != *argvec++ && (! strcmp(ext, lang_suffix())
454                 )) {
455                         compile_cnt++;
456                 }
457         }
458
459         if (compile_cnt > 1 && c_flag && o_flag) {
460                 warning("-o flag ignored");
461                 o_flag = 0;
462         }
463
464 #ifdef FM2
465         INCLUDE = expand_string("-I$H/lib/m2");
466 #endif /* FM2 */
467 #ifdef FCC
468         INCLUDE = expand_string(ansi_c ? "-I$H/include/tail_ac" : "-I$H/include/_tail_cc");
469         append(&COMP_FLAGS, "-L");
470 #endif /* FCC */
471         count = SRCFILES.al_argc;
472         argvec = &(SRCFILES.al_argv[0]);
473         while (count-- > 0) {
474                 register char *f;
475                 basename(file = *argvec++, BASE);
476
477                 ext = extension(file);
478
479                 if (file[0] != '-' &&
480                     ext != file && (!strcmp(ext, lang_suffix())
481                 )) {
482                         if (compile_cnt > 1) printf("%s\n", file);
483
484                         ldfile = c_flag ? ofile : alloc((unsigned)strlen(BASE)+3);
485                         if (
486 #ifdef FCC
487                             !strcmp(ext, "s") &&
488 #endif
489                             needsprep(file)) {
490                                 strcpy(tmp_file, TMP_DIR);
491                                 strcat(tmp_file, "/F_XXXXXX");
492                                 mktemp(tmp_file);
493                                 init(call);
494                                 append(call, CPP);
495                                 concat(call, &CPP_FLAGS);
496                                 append(call, INCLUDE);
497                                 append(call, file);
498                                 if (runvec(call, tmp_file)) {
499                                         file = tmp_file;
500                                 }
501                                 else {
502                                         remove(tmp_file);
503                                         tmp_file[0] = '\0';
504                                         continue;
505                                 }
506                         }
507                         init(call);
508                         if (o_flag && c_flag) {
509                                 f = o_FILE;
510                         }
511                         else    f = mkstr(ldfile, BASE, ".", "o", (char *)0);
512                                 append(call, COMP);
513 #ifdef FCC
514                                 concat(call, &CPP_FLAGS);
515 #endif
516                                 concat(call, &COMP_FLAGS);
517 #if FM2 || FCC
518                                 append(call, INCLUDE);
519 #endif
520                                 append(call, file);
521                                 append(call, f);
522                         if (runvec(call, (char *) 0)) {
523                                 file = f;
524                         }
525                         else {
526                                 remove(f);
527                                 continue;
528                         }
529                         cleanup(tmp_file);
530                         tmp_file[0] = '\0';
531                 }
532
533                 else if (file[0] != '-' &&
534                          strcmp(ext, "o") && strcmp(ext, "a")) {
535                         warning("file with unknown suffix (%s) passed to the loader", ext);
536                 }
537
538                 if (c_flag)
539                         continue;
540
541                 append(&LDFILES, file);
542         }
543
544         /* *.s to a.out */
545         if (RET_CODE == 0 && LDFILES.al_argc > 0) {
546                 init(call);
547                 expand(&LD_HEAD);
548                 cc = "cc.2g";
549                 expand(&LD_TAIL);
550                 append(call, expand_string(LD_NAME));
551                 concat(call, &align);
552                 append(call, "-o");
553                 strcpy(tmp_file, TMP_DIR);
554                 strcat(tmp_file, "/F_XXXXXX");
555                 mktemp(tmp_file);
556                 append(call, tmp_file);
557                 concat(call, &LD_HEAD);
558                 concat(call, &LD_FLAGS);
559                 concat(call, &LDFILES);
560                 if (g_flag) append(call, expand_string("$H/lib/$M/tail_db"));
561 #ifdef FCC
562                 if (! ansi_c) append(call, expand_string("$H/lib/$S/tail_cc.1s"));
563 #endif
564                 concat(call, &LD_TAIL);
565                 if (! runvec(call, (char *) 0)) {
566                         cleanup(tmp_file);
567                         exit(RET_CODE);
568                 }
569                 init(call);
570                 append(call, expand_string(CV_NAME));
571                 append(call, tmp_file);
572                 append(call, o_FILE);
573                 runvec(call, (char *) 0);
574                 cleanup(tmp_file);
575         }
576         exit(RET_CODE);
577 }
578
579 needsprep(name)
580         char *name;
581 {
582         int file;
583         char fc;
584
585         file = open(name,0);
586         if (file < 0) return 0;
587         if (read(file, &fc, 1) != 1) fc = 0;
588         close(file);
589         return fc == '#';
590 }
591
592 char *
593 alloc(u)
594         unsigned u;
595 {
596         char *p = malloc(u);
597
598         if (p == 0)
599                 panic("no space");
600         return p;
601 }
602
603 char *
604 expand_string(s)
605         char    *s;
606 {
607         char    buf[1024];
608         register char   *p = s;
609         register char   *q = &buf[0];
610         int expanded = 0;
611
612         if (!p) return p;
613         while (*p) {
614                 if (*p == '$') {
615                         p++;
616                         expanded = 1;
617                         switch(*p++) {
618                         case 'A':
619                                 if (ansi_c) strcpy(q, "ac");
620                                 else strcpy(q, cc);
621                                 break;
622                         case 'H':
623                                 strcpy(q, EM_DIR);
624                                 break;
625                         case 'M':
626                                 strcpy(q, MACHNAME);
627                                 break;
628                         case 'S':
629                                 strcpy(q, SYSNAME);
630                                 break;
631                         default:
632                                 panic("internal error");
633                                 break;
634                         }
635                         while (*q) q++;
636                 }
637                 else *q++ = *p++;
638         }
639         if (! expanded) return s;
640         *q++ = '\0';
641         p = alloc((unsigned int) (q - buf));
642         return strcpy(p, buf);
643 }
644
645 append(al, arg)
646         register struct arglist *al;
647         char *arg;
648 {
649         if (!arg || !*arg) return;
650         if (al->al_argc >= MAXARGC)
651                 panic("argument list overflow");
652         al->al_argv[(al->al_argc)++] = arg;
653 }
654
655 expand(al)
656         register struct arglist *al;
657 {
658         register int i = al->al_argc;
659         register char **p = &(al->al_argv[0]);
660
661         while (i-- > 0) {
662                 *p = expand_string(*p);
663                 p++;
664         }
665 }
666
667 concat(al1, al2)
668         struct arglist *al1, *al2;
669 {
670         register i = al2->al_argc;
671         register char **p = &(al1->al_argv[al1->al_argc]);
672         register char **q = &(al2->al_argv[0]);
673
674         if ((al1->al_argc += i) >= MAXARGC)
675                 panic("argument list overflow");
676         while (i-- > 0) {
677                 *p++ = *q++;
678         }
679 }
680 #if __STDC__
681 /*VARARGS*/
682 char *
683 mkstr(char *dst, ...)
684 {
685         va_list ap;
686
687         va_start(ap, dst);
688         {
689                 register char *p;
690                 register char *q;
691
692                 q = dst;
693                 p = va_arg(ap, char *);
694
695                 while (p) {
696                         while (*q++ = *p++);
697                         q--;
698                         p = va_arg(ap, char *);
699                 }
700         }
701         va_end(ap);
702
703         return dst;
704 }
705 #else
706 /*VARARGS*/
707 char *
708 mkstr(va_alist)
709         va_dcl
710 {
711         va_list ap;
712         char *dst;
713
714         va_start(ap);
715         {
716                 register char *p;
717                 register char *q;
718
719                 dst = q = va_arg(ap, char *);
720                 p = va_arg(ap, char *);
721
722                 while (p) {
723                         while (*q++ = *p++);
724                         q--;
725                         p = va_arg(ap, char *);
726                 }
727         }
728         va_end(ap);
729
730         return dst;
731 }
732 #endif
733 basename(str, dst)
734         char *str;
735         register char *dst;
736 {
737         register char *p1 = str;
738         register char *p2 = p1;
739
740         while (*p1)
741                 if (*p1++ == '/')
742                         p2 = p1;
743         p1--;
744         while (*p1 != '.' && p1 >= p2) p1--;
745         if (p1 >= p2) {
746                 *p1 = '\0';
747                 while (*dst++ = *p2++);
748                 *p1 = '.';
749         }
750         else
751                 while (*dst++ = *p2++);
752 }
753
754 char *
755 extension(fn)
756         char *fn;
757 {
758         register char *c = fn;
759
760         while (*c++) ;
761         while (*--c != '.' && c >= fn) { }
762         if (c++ < fn || !*c) return fn;
763         return c;
764 }
765
766 runvec(vec, outp)
767         struct arglist *vec;
768         char *outp;
769 {
770         int pid, status;
771
772         if (v_flag) {
773                 pr_vec(vec);
774                 putc('\n', stderr);
775         }
776         if ((pid = fork()) == 0) {      /* start up the process */
777                 if (outp) {     /* redirect standard output     */
778                         close(1);
779                         if (creat(outp, 0666) != 1)
780                                 panic("cannot create output file");
781                 }
782                 ex_vec(vec);
783         }
784         if (pid == -1)
785                 panic("no more processes");
786         kids = pid;
787         wait(&status);
788         if (status) switch(status & 0177) {
789         case SIGHUP:
790         case SIGINT:
791         case SIGQUIT:
792         case SIGTERM:
793         case 0:
794                 break;
795         default:
796                 error("%s died with signal %d\n", vec->al_argv[1], status&0177);
797         }
798         kids = -1;
799         return status ? ((RET_CODE = 1), 0) : 1;
800 }
801
802 /*VARARGS1*/
803 error(str, s1, s2)
804         char *str, *s1, *s2;
805 {
806         fprintf(stderr, "%s: ", ProgCall);
807         fprintf(stderr, str, s1, s2);
808         putc('\n', stderr);
809         ecount++;
810 }
811
812 /*VARARGS1*/
813 warning(str, s1, s2)
814         char *str, *s1, *s2;
815 {
816         fprintf(stderr, "%s: (warning) ", ProgCall);
817         fprintf(stderr, str, s1, s2);
818         putc('\n', stderr);
819 }
820
821 panic(str)
822         char *str;
823 {
824         error(str);
825         trapcc(SIGINT);
826 }
827
828 pr_vec(vec)
829         register struct arglist *vec;
830 {
831         register char **ap = &vec->al_argv[1];
832
833         vec->al_argv[vec->al_argc] = 0;
834         fprintf(stderr, "%s", *ap);
835         while (*++ap) {
836                 fprintf(stderr, " %s", *ap);
837         }
838 }
839
840 extern int errno;
841
842 ex_vec(vec)
843         register struct arglist *vec;
844 {
845         if (noexec)
846                 exit(0);
847         vec->al_argv[vec->al_argc] = 0;
848         execv(vec->al_argv[1], &(vec->al_argv[1]));
849         if (errno == ENOEXEC) { /* not an a.out, try it with the SHELL */
850                 vec->al_argv[0] = SHELL;
851                 execv(SHELL, &(vec->al_argv[0]));
852         }
853         if (access(vec->al_argv[1], 1) == 0) {
854                 /* File is executable. */
855                 error("cannot execute %s", vec->al_argv[1]);
856         } else {
857                 error("%s is not executable", vec->al_argv[1]);
858         }
859         exit(1);
860 }