2
* lcc [ option ]... [ file | -llib ]...
3
* front end for the ANSI C compiler
5
static char rcsid[] = "Id: dummy rcsid";
17
#define TEMPDIR "/tmp"
20
typedef struct list *List;
21
struct list { /* circular list nodes: */
22
char *str; /* option or file name */
23
List link; /* next list element */
26
static void *alloc(int);
27
static List append(char *,List);
28
extern char *basename(char *);
29
static int callsys(char *[]);
30
extern char *concat(char *, char *);
31
static int compile(char *, char *);
32
static void compose(char *[], List, List, List);
33
static void error(char *, char *);
34
static char *exists(char *);
35
static char *first(char *);
36
static int filename(char *, char *);
37
static List find(char *, List);
38
static void help(void);
39
static void initinputs(void);
40
static void interrupt(int);
41
static void opt(char *);
42
static List path2list(const char *);
43
extern int main(int, char *[]);
44
extern char *replace(const char *, int, int);
46
extern char *strsave(const char *);
47
extern char *stringf(const char *, ...);
48
extern int suffix(char *, char *[], int);
49
extern char *tempname(char *);
52
extern int getpid(void);
55
extern char *cpp[], *include[], *com[], *as[],*ld[], inputs[], *suffixes[];
56
extern int option(char *);
58
static int errcnt; /* number of errors */
59
static int Eflag; /* -E specified */
60
static int Sflag = 1; /* -S specified */ //for Q3 we always generate asm
61
static int cflag; /* -c specified */
62
static int verbose; /* incremented for each -v */
63
static List llist[2]; /* loader files, flags */
64
static List alist; /* assembler flags */
65
static List clist; /* compiler flags */
66
static List plist; /* preprocessor flags */
67
static List ilist; /* list of additional includes from LCCINPUTS */
68
static List rmlist; /* list of files to remove */
69
static char *outfile; /* ld output file or -[cS] object file */
70
static int ac; /* argument count */
71
static char **av; /* argument vector */
72
char *tempdir = TEMPDIR; /* directory for temporary files */
73
static char *progname;
74
static List lccinputs; /* list of input directories */
76
extern void UpdatePaths( const char *lccBinary );
78
int main(int argc, char *argv[]) {
83
UpdatePaths( progname );
86
av = alloc(ac*sizeof(char *));
87
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
88
signal(SIGINT, interrupt);
89
if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
90
signal(SIGTERM, interrupt);
92
if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
93
signal(SIGHUP, interrupt);
96
tempdir = getenv("TMP");
97
else if (getenv("TEMP"))
98
tempdir = getenv("TEMP");
99
else if (getenv("TMPDIR"))
100
tempdir = getenv("TMPDIR");
103
for (; (i > 0 && tempdir[i-1] == '/') || tempdir[i-1] == '\\'; i--)
109
plist = append("-D__LCC__", 0);
111
if (getenv("LCCDIR"))
112
option(stringf("-lccdir=%s", getenv("LCCDIR")));
113
for (nf = 0, i = j = 1; i < argc; i++) {
114
if (strcmp(argv[i], "-o") == 0) {
116
if (suffix(argv[i], suffixes, 2) >= 0) {
117
error("-o would overwrite %s", argv[i]);
123
error("unrecognized option `%s'", argv[i-1]);
126
} else if (strcmp(argv[i], "-target") == 0) {
127
if (argv[i+1] && *argv[i+1] != '-')
130
} else if (*argv[i] == '-' && argv[i][1] != 'l') {
133
} else if (*argv[i] != '-' && suffix(argv[i], suffixes, 3) >= 0)
137
if ((cflag || Sflag) && outfile && nf != 1) {
138
fprintf(stderr, "%s: -o %s ignored\n", progname, outfile);
142
for (i = 0; include[i]; i++)
143
plist = append(include[i], plist);
148
plist = append(b->str, plist);
149
} while (b != ilist);
152
for (i = 1; argv[i]; i++)
156
char *name = exists(argv[i]);
158
if (strcmp(name, argv[i]) != 0
159
|| (nf > 1 && suffix(name, suffixes, 3) >= 0))
160
fprintf(stderr, "%s:\n", name);
163
error("can't find `%s'", argv[i]);
165
if (errcnt == 0 && !Eflag && !Sflag && !cflag && llist[1]) {
166
compose(ld, llist[0], llist[1],
167
append(outfile ? outfile : concat("a", first(suffixes[4])), 0));
172
return errcnt ? EXIT_FAILURE : EXIT_SUCCESS;
175
/* alloc - allocate n bytes or die */
176
static void *alloc(int n) {
177
static char *avail, *limit;
179
n = (n + sizeof(char *) - 1)&~(sizeof(char *) - 1);
180
if (n >= limit - avail) {
181
avail = malloc(n + 4*1024);
183
limit = avail + n + 4*1024;
189
/* append - append a node with string str onto list, return new list */
190
static List append(char *str, List list) {
191
List p = alloc(sizeof *p);
195
p->link = list->link;
202
/* basename - return base name for name, e.g. /usr/drh/foo.c => foo */
203
char *basename(char *name) {
206
for (b = s = name; *s; s++)
207
if (*s == '/' || *s == '\\') {
210
} else if (*s == '.')
223
extern int fork(void);
225
extern int wait(int *);
227
static int _spawnvp(int mode, const char *cmdname, char *argv[]) {
230
switch (pid = fork()) {
232
fprintf(stderr, "%s: no more processes\n", progname);
235
// TTimo removing hardcoded paths, searching in $PATH
236
execvp(cmdname, argv);
237
fprintf(stderr, "%s: ", progname);
242
while ((n = wait(&status)) != pid && n != -1)
247
fprintf(stderr, "%s: fatal error in %s\n", progname, cmdname);
250
return (status>>8)&0377;
254
/* callsys - execute the command described by av[0...], return status */
255
static int callsys(char **av) {
261
for (i = 0; av[i] != NULL; i++)
266
argv = malloc(argc*sizeof *argv);
268
argv = realloc(argv, argc*sizeof *argv);
271
for (i = 0; status == 0 && av[i] != NULL; ) {
274
for ( ; av[i] != NULL && (s = strchr(av[i], '\n')) == NULL; i++)
278
argv[j++] = stringf("%.*s", s - av[i], av[i]);
285
executable = strsave( argv[0] );
286
argv[0] = stringf( "\"%s\"", argv[0] );
289
fprintf(stderr, "%s", argv[0]);
290
for (k = 1; argv[k] != NULL; k++)
291
fprintf(stderr, " %s", argv[k]);
292
fprintf(stderr, "\n");
296
status = _spawnvp(_P_WAIT, executable, argv);
298
status = _spawnvp(_P_WAIT, executable, (const char* const*)argv);
301
fprintf(stderr, "%s: ", progname);
308
/* concat - return concatenation of strings s1 and s2 */
309
char *concat(char *s1, char *s2) {
311
char *s = alloc(n + strlen(s2) + 1);
318
/* compile - compile src into dst, return status */
319
static int compile(char *src, char *dst) {
320
compose(com, clist, append(src, 0), append(dst, 0));
324
/* compose - compose cmd into av substituting a, b, c for $1, $2, $3, resp. */
325
static void compose(char *cmd[], List a, List b, List c) {
332
for (i = j = 0; cmd[i]; i++) {
333
char *s = strchr(cmd[i], '$');
334
if (s && isdigit(s[1])) {
336
assert(k >=1 && k <= 3);
337
if ((b = lists[k-1])) {
339
av[j] = alloc(strlen(cmd[i]) + strlen(b->str) - 1);
340
strncpy(av[j], cmd[i], s - cmd[i]);
341
av[j][s-cmd[i]] = '\0';
342
strcat(av[j], b->str);
343
strcat(av[j++], s + 2);
344
while (b != lists[k-1]) {
350
} else if (*cmd[i]) {
358
/* error - issue error msg according to fmt, bump error count */
359
static void error(char *fmt, char *msg) {
360
fprintf(stderr, "%s: ", progname);
361
fprintf(stderr, fmt, msg);
362
fprintf(stderr, "\n");
366
/* exists - if `name' readable return its path name or return null */
367
static char *exists(char *name) {
370
if ( (name[0] == '/' || name[0] == '\\' || name[2] == ':')
371
&& access(name, 4) == 0)
373
if (!(name[0] == '/' || name[0] == '\\' || name[2] == ':')
379
sprintf(buf, "%s/%s", b->str, name);
380
if (access(buf, 4) == 0)
382
} else if (access(name, 4) == 0)
384
} while (b != lccinputs);
390
/* first - return first component in semicolon separated list */
391
static char *first(char *list) {
392
char *s = strchr(list, ';');
396
strncpy(buf, list, s-list);
403
/* filename - process file name argument `name', return status */
404
static int filename(char *name, char *base) {
406
static char *stemp, *itemp;
409
base = basename(name);
410
switch (suffix(name, suffixes, 4)) {
411
case 0: /* C source files */
412
compose(cpp, plist, append(name, 0), 0);
414
status = callsys(av);
418
itemp = tempname(first(suffixes[1]));
419
compose(cpp, plist, append(name, 0), append(itemp, 0));
420
status = callsys(av);
422
return filename(itemp, base);
424
case 1: /* preprocessed source files */
428
status = compile(name, outfile ? outfile : concat(base, first(suffixes[2])));
429
else if ((status = compile(name, stemp?stemp:(stemp=tempname(first(suffixes[2]))))) == 0)
430
return filename(stemp, base);
432
case 2: /* assembly language files */
437
if (cflag && outfile)
440
ofile = concat(base, first(suffixes[3]));
442
ofile = tempname(first(suffixes[3]));
443
compose(as, alist, append(name, 0), append(ofile, 0));
444
status = callsys(av);
445
if (!find(ofile, llist[1]))
446
llist[1] = append(ofile, llist[1]);
449
case 3: /* object files */
450
if (!find(name, llist[1]))
451
llist[1] = append(name, llist[1]);
455
compose(cpp, plist, append(name, 0), 0);
456
status = callsys(av);
458
llist[1] = append(name, llist[1]);
466
/* find - find 1st occurrence of str in list, return list node or 0 */
467
static List find(char *str, List list) {
472
if (strcmp(str, b->str) == 0)
474
} while ((b = b->link) != list);
478
/* help - print help message */
479
static void help(void) {
480
static char *msgs[] = {
481
"", " [ option | file ]...\n",
482
" except for -l, options are processed left-to-right before files\n",
483
" unrecognized options are taken to be linker options\n",
484
"-A warn about nonANSI usage; 2nd -A warns more\n",
485
"-b emit expression-level profiling code; see bprint(1)\n",
487
"-Bstatic -Bdynamic specify static or dynamic libraries\n",
489
"-Bdir/ use the compiler named `dir/rcc'\n",
491
"-dn set switch statement density to `n'\n",
492
"-Dname -Dname=def define the preprocessor symbol `name'\n",
493
"-E run only the preprocessor on the named C programs and unsuffixed files\n",
494
"-g produce symbol table information for debuggers\n",
495
"-help or -? print this message\n",
496
"-Idir add `dir' to the beginning of the list of #include directories\n",
497
"-lx search library `x'\n",
498
"-N do not search the standard directories for #include files\n",
499
"-n emit code to check for dereferencing zero pointers\n",
501
"-o file leave the output in `file'\n",
502
"-P print ANSI-style declarations for globals\n",
503
"-p -pg emit profiling code; see prof(1) and gprof(1)\n",
504
"-S compile to assembly language\n",
506
"-static specify static libraries (default is dynamic)\n",
508
"-t -tname emit function tracing calls to printf or to `name'\n",
509
"-target name is ignored\n",
510
"-tempdir=dir place temporary files in `dir/'", "\n"
511
"-Uname undefine the preprocessor symbol `name'\n",
512
"-v show commands as they are executed; 2nd -v suppresses execution\n",
513
"-w suppress warnings\n",
514
"-Woarg specify system-specific `arg'\n",
515
"-W[pfal]arg pass `arg' to the preprocessor, compiler, assembler, or linker\n",
521
for (i = 0; msgs[i]; i++) {
522
fprintf(stderr, "%s", msgs[i]);
523
if (strncmp("-tempdir", msgs[i], 8) == 0 && tempdir)
524
fprintf(stderr, "; default=%s", tempdir);
526
#define xx(v) if ((s = getenv(#v))) fprintf(stderr, #v "=%s\n", s)
536
/* initinputs - if LCCINPUTS or include is defined, use them to initialize various lists */
537
static void initinputs(void) {
538
char *s = getenv("LCCINPUTS");
544
if (s == 0 || (s = inputs)[0] == 0)
547
lccinputs = path2list(s);
551
if (strcmp(b->str, ".") != 0) {
552
ilist = append(concat("-I", b->str), ilist);
553
if (strstr(com[1], "win32") == NULL)
554
llist[0] = append(concat("-L", b->str), llist[0]);
557
} while (b != lccinputs);
560
if ((list = b = path2list(getenv("include"))))
563
ilist = append(stringf("-I\"%s\"", b->str), ilist);
568
/* interrupt - catch interrupt signals */
569
static void interrupt(int n) {
574
/* opt - process option in arg */
575
static void opt(char *arg) {
576
switch (arg[1]) { /* multi-character options */
577
case 'W': /* -Wxarg */
578
if (arg[2] && arg[3])
585
plist = append(&arg[3], plist);
588
if (strcmp(&arg[3], "-C") || option("-b")) {
589
clist = append(&arg[3], clist);
592
break; /* and fall thru */
594
alist = append(&arg[3], alist);
597
llist[0] = append(&arg[3], llist[0]);
600
fprintf(stderr, "%s: %s ignored\n", progname, arg);
604
clist = append(arg, clist);
606
case 't': /* -t -tname -tempdir=dir */
607
if (strncmp(arg, "-tempdir=", 9) == 0)
610
clist = append(arg, clist);
612
case 'p': /* -p -pg */
614
clist = append(arg, clist);
616
fprintf(stderr, "%s: %s ignored\n", progname, arg);
618
case 'D': /* -Dname -Dname=def */
619
case 'U': /* -Uname */
620
case 'I': /* -Idir */
621
plist = append(arg, plist);
623
case 'B': /* -Bdir -Bstatic -Bdynamic */
625
if (strcmp(arg, "-Bstatic") == 0 || strcmp(arg, "-Bdynamic") == 0)
626
llist[1] = append(arg, llist[1]);
632
error("-B overwrites earlier option", 0);
634
if (strstr(com[1], "win32") != NULL)
635
com[0] = concat(replace(path, '/', '\\'), concat("rcc", first(suffixes[4])));
637
com[0] = concat(path, "rcc");
639
error("missing directory in -B option", 0);
643
if (strcmp(arg, "-help") == 0) {
644
static int printed = 0;
653
if (strcmp(arg,"-static") == 0) {
655
fprintf(stderr, "%s: %s ignored\n", progname, arg);
661
switch (arg[1]) { /* single-character options */
666
fprintf(stderr, "%s: %s ignored\n", progname, arg);
668
case 'A': case 'n': case 'w': case 'P':
669
clist = append(arg, clist);
673
clist = append(arg[1] == 'g' ? "-g2" : arg, clist);
675
fprintf(stderr, "%s: %s ignored\n", progname, arg);
679
clist = append("-g3", clist);
680
llist[0] = append("-N", llist[0]);
682
fprintf(stderr, "%s: %s ignored\n", progname, arg);
691
if (strcmp(basename(cpp[0]), "gcc-cpp") == 0)
692
plist = append("-nostdinc", plist);
697
if (verbose++ == 0) {
698
if (strcmp(basename(cpp[0]), "gcc-cpp") == 0)
699
plist = append(arg, plist);
700
clist = append(arg, clist);
701
fprintf(stderr, "%s %s\n", progname, rcsid);
705
if (cflag || Sflag || Eflag)
706
fprintf(stderr, "%s: %s ignored\n", progname, arg);
708
llist[1] = append(arg, llist[1]);
711
/* path2list - convert a colon- or semicolon-separated list to a list */
712
static List path2list(const char *path) {
718
if (strchr(path, ';'))
722
if ((p = strchr(path, sep))) {
723
assert(p - path < sizeof buf);
724
strncpy(buf, path, p - path);
727
assert(strlen(path) < sizeof buf);
730
if (!find(buf, list))
731
list = append(strsave(buf), list);
739
/* replace - copy str, then replace occurrences of from with to, return the copy */
740
char *replace(const char *str, int from, int to) {
741
char *s = strsave(str), *p = s;
743
for ( ; (p = strchr(p, from)) != NULL; p++)
748
/* rm - remove files in list */
749
static void rm(List list) {
753
fprintf(stderr, "rm");
756
fprintf(stderr, " %s", b->str);
759
} while ((b = b->link) != list);
761
fprintf(stderr, "\n");
765
/* strsave - return a saved copy of string str */
766
char *strsave(const char *str) {
767
return strcpy(alloc(strlen(str)+1), str);
770
/* stringf - format and return a string */
771
char *stringf(const char *fmt, ...) {
777
n = vsprintf(buf, fmt, ap);
782
/* suffix - if one of tails[0..n-1] holds a proper suffix of name, return its index */
783
int suffix(char *name, char *tails[], int n) {
784
int i, len = strlen(name);
786
for (i = 0; i < n; i++) {
787
char *s = tails[i], *t;
788
for ( ; (t = strchr(s, ';')); s = t + 1) {
790
if (len > m && strncmp(&name[len-m], s, m) == 0)
795
if (len > m && strncmp(&name[len-m], s, m) == 0)
802
/* tempname - generate a temporary file name in tempdir with given suffix */
803
char *tempname(char *suffix) {
805
char *name = stringf("%s/lcc%d%d%s", tempdir, getpid(), n++, suffix);
807
if (strstr(com[1], "win32") != NULL)
808
name = replace(name, '/', '\\');
809
rmlist = append(name, rmlist);