Pristine Ack-5.5
[Ack-5.5.git] / fcc / driver / fcc.c
1 /*      fcc
2         Driver for fast cc-compatible ACK C compiler.
3
4         Derived from the C compiler driver from Minix.
5
6         Compile this file with
7                 cc -O -I<EM home dir>/config driver.c
8         Install the resulting binaries in the EM bin directory.
9         Suggested name: fcc
10 */
11
12 #ifdef sun3
13 #define MACHNAME        "m68020"
14 #define SYSNAME         "sun3"
15 #endif
16
17 #ifdef vax4
18 #define MACHNAME        "vax4"
19 #define SYSNAME         "vax4"
20 #endif
21
22 #include <errno.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <em_path.h>
26 #if __STDC__
27 #include <stdarg.h>
28 #else
29 #include <varargs.h>
30 #endif
31
32
33 /*
34         Version producing cc-compatible .o files in one pass.
35 */
36 #define MAXARGC 256     /* maximum number of arguments allowed in a list */
37 #define USTR_SIZE       128     /* maximum length of string variable */
38
39 typedef char USTRING[USTR_SIZE];
40
41 struct arglist {
42         int al_argc;
43         char *al_argv[MAXARGC];
44 };
45
46 #define CPP_NAME        "$H/lib.bin/cpp"
47 #define LD_NAME         "/bin/ld"
48 #define AS_NAME         "/bin/as"
49 #define SHELL           "/bin/sh"
50
51 char    *CPP;
52 char    *COMP;
53
54 int kids =  -1;
55 int ecount = 0;
56
57 struct arglist CPP_FLAGS = {
58         7,
59         {
60                 "-Dunix",
61                 "-D_EM_WSIZE=4",
62                 "-D_EM_PSIZE=4",
63                 "-D_EM_SSIZE=2",
64                 "-D_EM_LSIZE=4",
65                 "-D_EM_FSIZE=4",
66                 "-D_EM_DSIZE=8",
67         }
68 };
69
70 struct arglist LD_HEAD = {
71 #ifdef sun3
72         8,
73         {
74                 "-dc",
75                 "-dp",
76                 "-e",
77                 "start",
78                 "-X",
79                 "-L/usr/lib/fsoft",
80                 "/usr/lib/crt0.o",
81                 "/usr/lib/Fcrt1.o"
82         }
83 #endif
84 #ifdef vax4
85         2,
86         {
87                 "-X",
88                 "/lib/crt0.o"
89         }
90 #endif
91 };
92
93 struct arglist LD_TAIL = {
94         2,
95         {
96                 "$H/lib/$S/tail_ext",
97                 "-lc"
98         }
99 };
100
101 struct arglist LD_FLAGS;
102
103 struct arglist COMP_FLAGS;
104
105 char *o_FILE = "a.out"; /* default name for executable file */
106
107 #define remove(str)     ((noexec || unlink(str)), (str)[0] = '\0')
108 #define cleanup(str)            (str && str[0] && remove(str))
109 #define init(al)                ((al)->al_argc = 1)
110
111 char ProgCall[128];
112
113 struct arglist SRCFILES;
114 struct arglist LDFILES;
115
116 int RET_CODE = 0;
117
118 struct arglist CALL_VEC;
119
120 int o_flag = 0;
121 int c_flag = 0;
122 int v_flag = 0;
123 int O_flag = 0;
124
125 #if __STDC__
126 char *mkstr(char *, ...);
127 #else
128 char *mkstr();
129 #endif
130 char *malloc();
131 char *alloc();
132 char *extension();
133 char *expand_string();
134
135 USTRING ofile;
136 USTRING BASE;
137 USTRING tmp_file;
138
139 int noexec = 0;
140
141 extern char *strcat(), *strcpy(), *mktemp(), *strchr();
142
143 trapcc(sig)
144         int sig;
145 {
146         signal(sig, SIG_IGN);
147         if (kids != -1) kill(kids, sig);
148         cleanup(ofile);
149         cleanup(tmp_file);
150         exit(1);
151 }
152
153 #define lang_suffix()   "c"
154 #define comp_name()     "$H/lib.bin/c_cccompat"
155
156 int
157 lang_opt(str)
158         char *str;
159 {
160         switch(str[1]) {
161         case '-':       /* debug options */
162         case 'R':       /* strict K&R */
163         case 'w':       /* disable warnings */
164                 append(&COMP_FLAGS, str);
165                 return 1;
166         }
167         return 0;
168 }
169
170 main(argc, argv)
171         char *argv[];
172 {
173         char *str;
174         char **argvec;
175         int count;
176         char *ext;
177         register struct arglist *call = &CALL_VEC;
178         char *file;
179         char *ldfile;
180         int compile_cnt = 0;
181
182         setbuf(stdout, (char *) 0);
183         basename(*argv++,ProgCall);
184
185         COMP = expand_string(comp_name());
186         CPP = expand_string(CPP_NAME);
187
188 #ifdef vax4
189         append(&CPP_FLAGS, "-Dvax");
190 #endif
191 #ifdef sun3
192         append(&CPP_FLAGS, "-Dsun");
193         append(&CPP_FLAGS, "-Dmc68020");
194         append(&CPP_FLAGS, "-Dmc68000");
195 #endif
196
197         if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
198                 signal(SIGHUP, trapcc);
199         if (signal(SIGINT, SIG_IGN) != SIG_IGN)
200                 signal(SIGINT, trapcc);
201         if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
202                 signal(SIGQUIT, trapcc);
203         while (--argc > 0) {
204                 if (*(str = *argv++) != '-') {
205                         append(&SRCFILES, str);
206                         continue;
207                 }
208
209                 if (lang_opt(str)) {
210                 }
211                 else switch (str[1]) {
212
213                 case 'c':       /* stop after producing .o files */
214                         c_flag = 1;
215                         break;
216                 case 'D':       /* preprocessor #define */
217                 case 'U':       /* preprocessor #undef */
218                         append(&CPP_FLAGS, str);
219                         break;
220                 case 'I':       /* include directory */
221                         append(&CPP_FLAGS, str);
222                         break;
223                 case 'g':       /* debugger support */
224                         append(&COMP_FLAGS, str);
225                         break;
226                 case 'o':       /* target file */
227                         if (argc-- >= 0) {
228                                 o_flag = 1;
229                                 o_FILE = *argv++;
230                                 ext = extension(o_FILE);
231                                 if (ext != o_FILE && ! strcmp(ext, lang_suffix())
232                                 ) {
233                                         error("-o would overwrite %s", o_FILE);
234                                 }
235                         }
236                         break;
237                 case 'u':       /* mark identifier as undefined */
238                         append(&LD_FLAGS, str);
239                         if (argc-- >= 0)
240                                 append(&LD_FLAGS, *argv++);
241                         break;
242                 case 'O':       /* use built in peephole optimizer */
243                         O_flag = 1;
244                         break;
245                 case 'v':       /* verbose */
246                         v_flag++;
247                         if (str[2] == 'n')
248                                 noexec = 1;
249                         break;
250                 case 'l':       /* library file */
251                         append(&SRCFILES, str);
252                         break;
253                 case 't':       /* -target? */
254                         if (! strcmp(str, "-target")) {
255                                 if (argc-- >= 0) argv++;
256                                 break;
257                         }
258                         warning("%s flag ignored", str);
259                         break;
260                 case 'M':       /* use other compiler (for testing) */
261                         strcpy(COMP, str+2);
262                         break;
263                 case 's':       /* strip, -sun3? */
264                         if (! strcmp(str, "-sun3")) {
265                                 break;
266                         }
267                         /* fall through */
268                 case 'n':       /* text not read-only */
269                 case 'N':       /* text read-only */
270                 case 'r':       /* relocation produced */
271                 case 'S':       /* strip, but leave locals and globals */
272                         if (str[2] == '\0') {
273                                 append(&LD_FLAGS, str);
274                                 break;
275                         }
276                         /* fall through */
277                 default:
278                         warning("%s flag ignored", str);
279                         break;
280                 }
281         }
282
283         if (ecount) exit(1);
284
285         count = SRCFILES.al_argc;
286         argvec = &(SRCFILES.al_argv[0]);
287         while (count-- > 0) {
288                 ext = extension(*argvec);
289                 if (*argvec[0] != '-' && 
290                     ext != *argvec++ && (! strcmp(ext, lang_suffix())
291                 )) {
292                         compile_cnt++;
293                 }
294         }
295
296         if (compile_cnt > 1 && c_flag && o_flag) {
297                 warning("-o flag ignored");
298                 o_flag = 0;
299         }
300
301         append(&COMP_FLAGS, "-L");
302         count = SRCFILES.al_argc;
303         argvec = &(SRCFILES.al_argv[0]);
304         while (count-- > 0) {
305                 register char *f;
306                 basename(file = *argvec++, BASE);
307
308                 ext = extension(file);
309
310                 if (file[0] != '-' &&
311                     ext != file && (!strcmp(ext, lang_suffix())
312                 )) {
313                         if (compile_cnt > 1) printf("%s\n", file);
314
315                         ldfile = c_flag ? ofile : alloc((unsigned)strlen(BASE)+3);
316                         if (
317                             !strcmp(ext, "s") &&
318                             needsprep(file)) {
319                                 strcpy(tmp_file, TMP_DIR);
320                                 strcat(tmp_file, "/F_XXXXXX");
321                                 mktemp(tmp_file);
322                                 init(call);
323                                 append(call, CPP);
324                                 concat(call, &CPP_FLAGS);
325                                 append(call, file);
326                                 if (runvec(call, tmp_file)) {
327                                         file = tmp_file;
328                                 }
329                                 else {
330                                         remove(tmp_file);
331                                         tmp_file[0] = '\0';
332                                         continue;
333                                 }
334                         }
335                         init(call);
336                         if (o_flag && c_flag) {
337                                 f = o_FILE;
338                         }
339                         else    f = mkstr(ldfile, BASE, ".", "o", (char *)0);
340                         if (strcmp(ext, "s")) {
341                                 append(call, COMP);
342                                 concat(call, &CPP_FLAGS);
343                                 concat(call, &COMP_FLAGS);
344                                 append(call, file);
345                                 append(call, f);
346                         }
347                         else {
348                                 append(call, AS_NAME);
349                                 append(call, "-o");
350                                 append(call, f);
351 #ifdef sun3
352                                 append(call, "-mc68020");
353 #endif
354                                 append(call, file);
355                         }
356                         if (runvec(call, (char *) 0)) {
357                                 file = f;
358                         }
359                         else {
360                                 remove(f);
361                                 continue;
362                         }
363                         cleanup(tmp_file);
364                         tmp_file[0] = '\0';
365                 }
366
367                 else if (file[0] != '-' &&
368                          strcmp(ext, "o") && strcmp(ext, "a")) {
369                         warning("file with unknown suffix (%s) passed to the loader", ext);
370                 }
371
372                 if (c_flag)
373                         continue;
374
375                 append(&LDFILES, file);
376         }
377
378         /* *.s to a.out */
379         if (RET_CODE == 0 && LDFILES.al_argc > 0) {
380                 init(call);
381                 expand(&LD_HEAD);
382                 expand(&LD_TAIL);
383                 append(call, expand_string(LD_NAME));
384                 concat(call, &LD_FLAGS);
385                 append(call, "-o");
386                 append(call, o_FILE);
387                 concat(call, &LD_HEAD);
388                 concat(call, &LDFILES);
389                 concat(call, &LD_TAIL);
390                 if (! runvec(call, (char *) 0)) {
391                         exit(RET_CODE);
392                 }
393         }
394         exit(RET_CODE);
395 }
396
397 needsprep(name)
398         char *name;
399 {
400         int file;
401         char fc;
402
403         file = open(name,0);
404         if (file < 0) return 0;
405         if (read(file, &fc, 1) != 1) fc = 0;
406         close(file);
407         return fc == '#';
408 }
409
410 char *
411 alloc(u)
412         unsigned u;
413 {
414         char *p = malloc(u);
415
416         if (p == 0)
417                 panic("no space");
418         return p;
419 }
420
421 char *
422 expand_string(s)
423         char    *s;
424 {
425         char    buf[1024];
426         register char   *p = s;
427         register char   *q = &buf[0];
428         int expanded = 0;
429
430         if (!p) return p;
431         while (*p) {
432                 if (*p == '$') {
433                         p++;
434                         expanded = 1;
435                         switch(*p++) {
436                         case 'H':
437                                 strcpy(q, EM_DIR);
438                                 break;
439                         case 'M':
440                                 strcpy(q, MACHNAME);
441                                 break;
442                         case 'S':
443                                 strcpy(q, SYSNAME);
444                                 break;
445                         default:
446                                 panic("internal error");
447                                 break;
448                         }
449                         while (*q) q++;
450                 }
451                 else *q++ = *p++;
452         }
453         if (! expanded) return s;
454         *q++ = '\0';
455         p = alloc((unsigned int) (q - buf));
456         return strcpy(p, buf);
457 }
458
459 append(al, arg)
460         register struct arglist *al;
461         char *arg;
462 {
463         if (!arg || !*arg) return;
464         if (al->al_argc >= MAXARGC)
465                 panic("argument list overflow");
466         al->al_argv[(al->al_argc)++] = arg;
467 }
468
469 expand(al)
470         register struct arglist *al;
471 {
472         register int i = al->al_argc;
473         register char **p = &(al->al_argv[0]);
474
475         while (i-- > 0) {
476                 *p = expand_string(*p);
477                 p++;
478         }
479 }
480
481 concat(al1, al2)
482         struct arglist *al1, *al2;
483 {
484         register i = al2->al_argc;
485         register char **p = &(al1->al_argv[al1->al_argc]);
486         register char **q = &(al2->al_argv[0]);
487
488         if ((al1->al_argc += i) >= MAXARGC)
489                 panic("argument list overflow");
490         while (i-- > 0) {
491                 *p++ = *q++;
492         }
493 }
494
495 #if __STDC__
496 /*VARARGS*/
497 char *
498 mkstr(char *dst, ...)
499 {
500         va_list ap;
501
502         va_start(ap, dst);
503         {
504                 register char *p;
505                 register char *q;
506
507                 q = dst;
508                 p = va_arg(ap, char *);
509
510                 while (p) {
511                         while (*q++ = *p++);
512                         q--;
513                         p = va_arg(ap, char *);
514                 }
515         }
516         va_end(ap);
517
518         return dst;
519 }
520 #else
521 /*VARARGS*/
522 char *
523 mkstr(va_alist)
524         va_dcl
525 {
526         va_list ap;
527         char *dst;
528
529         va_start(ap);
530         {
531                 register char *p;
532                 register char *q;
533
534                 dst = q = va_arg(ap, char *);
535                 p = va_arg(ap, char *);
536
537                 while (p) {
538                         while (*q++ = *p++);
539                         q--;
540                         p = va_arg(ap, char *);
541                 }
542         }
543         va_end(ap);
544
545         return dst;
546 }
547 #endif
548
549 basename(str, dst)
550         char *str;
551         register char *dst;
552 {
553         register char *p1 = str;
554         register char *p2 = p1;
555
556         while (*p1)
557                 if (*p1++ == '/')
558                         p2 = p1;
559         p1--;
560         while (*p1 != '.' && p1 >= p2) p1--;
561         if (p1 >= p2) {
562                 *p1 = '\0';
563                 while (*dst++ = *p2++);
564                 *p1 = '.';
565         }
566         else
567                 while (*dst++ = *p2++);
568 }
569
570 char *
571 extension(fn)
572         char *fn;
573 {
574         register char *c = fn;
575
576         while (*c++) ;
577         while (*--c != '.' && c >= fn) { }
578         if (c++ < fn || !*c) return fn;
579         return c;
580 }
581
582 runvec(vec, outp)
583         struct arglist *vec;
584         char *outp;
585 {
586         int pid, status;
587
588         if (v_flag) {
589                 pr_vec(vec);
590                 putc('\n', stderr);
591         }
592         if ((pid = fork()) == 0) {      /* start up the process */
593                 if (outp) {     /* redirect standard output     */
594                         close(1);
595                         if (creat(outp, 0666) != 1)
596                                 panic("cannot create output file");
597                 }
598                 ex_vec(vec);
599         }
600         if (pid == -1)
601                 panic("no more processes");
602         kids = pid;
603         wait(&status);
604         if (status) switch(status & 0177) {
605         case SIGHUP:
606         case SIGINT:
607         case SIGQUIT:
608         case SIGTERM:
609         case 0:
610                 break;
611         default:
612                 error("%s died with signal %d\n", vec->al_argv[1], status&0177);
613         }
614         kids = -1;
615         return status ? ((RET_CODE = 1), 0) : 1;
616 }
617
618 /*VARARGS1*/
619 error(str, s1, s2)
620         char *str, *s1, *s2;
621 {
622         fprintf(stderr, "%s: ", ProgCall);
623         fprintf(stderr, str, s1, s2);
624         putc('\n', stderr);
625         ecount++;
626 }
627
628 /*VARARGS1*/
629 warning(str, s1, s2)
630         char *str, *s1, *s2;
631 {
632         fprintf(stderr, "%s: (warning) ", ProgCall);
633         fprintf(stderr, str, s1, s2);
634         putc('\n', stderr);
635 }
636
637 panic(str)
638         char *str;
639 {
640         error(str);
641         trapcc(SIGINT);
642 }
643
644 pr_vec(vec)
645         register struct arglist *vec;
646 {
647         register char **ap = &vec->al_argv[1];
648
649         vec->al_argv[vec->al_argc] = 0;
650         fprintf(stderr, "%s", *ap);
651         while (*++ap) {
652                 fprintf(stderr, " %s", *ap);
653         }
654 }
655
656 extern int errno;
657
658 ex_vec(vec)
659         register struct arglist *vec;
660 {
661         if (noexec)
662                 exit(0);
663         vec->al_argv[vec->al_argc] = 0;
664         execv(vec->al_argv[1], &(vec->al_argv[1]));
665         if (errno == ENOEXEC) { /* not an a.out, try it with the SHELL */
666                 vec->al_argv[0] = SHELL;
667                 execv(SHELL, &(vec->al_argv[0]));
668         }
669         if (access(vec->al_argv[1], 1) == 0) {
670                 /* File is executable. */
671                 error("cannot execute %s", vec->al_argv[1]);
672         } else {
673                 error("%s is not executable", vec->al_argv[1]);
674         }
675         exit(1);
676 }