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
== '.')
221 static char *escapeDoubleQuotes(const char *string
) {
222 int stringLength
= strlen(string
);
223 int bufferSize
= stringLength
+ 1;
230 for (i
= 0; i
< stringLength
; i
++) {
231 if (string
[i
] == '"')
235 newString
= (char*)malloc(bufferSize
);
237 if (newString
== NULL
)
240 for (i
= 0, j
= 0; i
< stringLength
; i
++) {
241 if (string
[i
] == '"')
242 newString
[j
++] = '\\';
244 newString
[j
++] = string
[i
];
252 static int spawn(const char *cmdname
, char **argv
) {
254 char **newArgv
= argv
;
258 // _spawnvp removes double quotes from arguments, so we
259 // have to escape them manually
260 while (*newArgv
++ != NULL
)
263 newArgv
= (char **)malloc(sizeof(char*) * (argc
+ 1));
265 for (i
= 0; i
< argc
; i
++)
266 newArgv
[i
] = escapeDoubleQuotes(argv
[i
]);
268 newArgv
[argc
] = NULL
;
270 exitStatus
= _spawnvp(_P_WAIT
, cmdname
, (const char *const *)newArgv
);
272 for (i
= 0; i
< argc
; i
++)
283 extern int fork(void);
285 extern int wait(int *);
287 static int spawn(const char *cmdname
, char **argv
) {
290 switch (pid
= fork()) {
292 fprintf(stderr
, "%s: no more processes\n", progname
);
295 // TTimo removing hardcoded paths, searching in $PATH
296 execvp(cmdname
, argv
);
297 fprintf(stderr
, "%s: ", progname
);
302 while ((n
= wait(&status
)) != pid
&& n
!= -1)
307 fprintf(stderr
, "%s: fatal error in %s\n", progname
, cmdname
);
310 return (status
>>8)&0377;
314 /* callsys - execute the command described by av[0...], return status */
315 static int callsys(char **av
) {
321 for (i
= 0; av
[i
] != NULL
; i
++)
326 argv
= malloc(argc
*sizeof *argv
);
328 argv
= realloc(argv
, argc
*sizeof *argv
);
331 for (i
= 0; status
== 0 && av
[i
] != NULL
; ) {
334 for ( ; av
[i
] != NULL
&& (s
= strchr(av
[i
], '\n')) == NULL
; i
++)
338 argv
[j
++] = stringf("%.*s", s
- av
[i
], av
[i
]);
345 executable
= strsave( argv
[0] );
346 argv
[0] = stringf( "\"%s\"", argv
[0] );
349 fprintf(stderr
, "%s", argv
[0]);
350 for (k
= 1; argv
[k
] != NULL
; k
++)
351 fprintf(stderr
, " %s", argv
[k
]);
352 fprintf(stderr
, "\n");
355 status
= spawn(executable
, argv
);
357 fprintf(stderr
, "%s: ", progname
);
364 /* concat - return concatenation of strings s1 and s2 */
365 char *concat(char *s1
, char *s2
) {
367 char *s
= alloc(n
+ strlen(s2
) + 1);
374 /* compile - compile src into dst, return status */
375 static int compile(char *src
, char *dst
) {
376 compose(com
, clist
, append(src
, 0), append(dst
, 0));
380 /* compose - compose cmd into av substituting a, b, c for $1, $2, $3, resp. */
381 static void compose(char *cmd
[], List a
, List b
, List c
) {
388 for (i
= j
= 0; cmd
[i
]; i
++) {
389 char *s
= strchr(cmd
[i
], '$');
390 if (s
&& isdigit(s
[1])) {
392 assert(k
>=1 && k
<= 3);
393 if ((b
= lists
[k
-1])) {
395 av
[j
] = alloc(strlen(cmd
[i
]) + strlen(b
->str
) - 1);
396 strncpy(av
[j
], cmd
[i
], s
- cmd
[i
]);
397 av
[j
][s
-cmd
[i
]] = '\0';
398 strcat(av
[j
], b
->str
);
399 strcat(av
[j
++], s
+ 2);
400 while (b
!= lists
[k
-1]) {
406 } else if (*cmd
[i
]) {
414 /* error - issue error msg according to fmt, bump error count */
415 static void error(char *fmt
, char *msg
) {
416 fprintf(stderr
, "%s: ", progname
);
417 fprintf(stderr
, fmt
, msg
);
418 fprintf(stderr
, "\n");
422 /* exists - if `name' readable return its path name or return null */
423 static char *exists(char *name
) {
426 if ( (name
[0] == '/' || name
[0] == '\\' || name
[2] == ':')
427 && access(name
, 4) == 0)
429 if (!(name
[0] == '/' || name
[0] == '\\' || name
[2] == ':')
435 sprintf(buf
, "%s/%s", b
->str
, name
);
436 if (access(buf
, 4) == 0)
438 } else if (access(name
, 4) == 0)
440 } while (b
!= lccinputs
);
446 /* first - return first component in semicolon separated list */
447 static char *first(char *list
) {
448 char *s
= strchr(list
, ';');
452 strncpy(buf
, list
, s
-list
);
459 /* filename - process file name argument `name', return status */
460 static int filename(char *name
, char *base
) {
462 static char *stemp
, *itemp
;
465 base
= basename(name
);
466 switch (suffix(name
, suffixes
, 4)) {
467 case 0: /* C source files */
468 compose(cpp
, plist
, append(name
, 0), 0);
470 status
= callsys(av
);
474 itemp
= tempname(first(suffixes
[1]));
475 compose(cpp
, plist
, append(name
, 0), append(itemp
, 0));
476 status
= callsys(av
);
478 return filename(itemp
, base
);
480 case 1: /* preprocessed source files */
484 status
= compile(name
, outfile
? outfile
: concat(base
, first(suffixes
[2])));
485 else if ((status
= compile(name
, stemp
?stemp
:(stemp
=tempname(first(suffixes
[2]))))) == 0)
486 return filename(stemp
, base
);
488 case 2: /* assembly language files */
493 if (cflag
&& outfile
)
496 ofile
= concat(base
, first(suffixes
[3]));
498 ofile
= tempname(first(suffixes
[3]));
499 compose(as
, alist
, append(name
, 0), append(ofile
, 0));
500 status
= callsys(av
);
501 if (!find(ofile
, llist
[1]))
502 llist
[1] = append(ofile
, llist
[1]);
505 case 3: /* object files */
506 if (!find(name
, llist
[1]))
507 llist
[1] = append(name
, llist
[1]);
511 compose(cpp
, plist
, append(name
, 0), 0);
512 status
= callsys(av
);
514 llist
[1] = append(name
, llist
[1]);
522 /* find - find 1st occurrence of str in list, return list node or 0 */
523 static List
find(char *str
, List list
) {
528 if (strcmp(str
, b
->str
) == 0)
530 } while ((b
= b
->link
) != list
);
534 /* help - print help message */
535 static void help(void) {
536 static char *msgs
[] = {
537 "", " [ option | file ]...\n",
538 " except for -l, options are processed left-to-right before files\n",
539 " unrecognized options are taken to be linker options\n",
540 "-A warn about nonANSI usage; 2nd -A warns more\n",
541 "-b emit expression-level profiling code; see bprint(1)\n",
543 "-Bstatic -Bdynamic specify static or dynamic libraries\n",
545 "-Bdir/ use the compiler named `dir/rcc'\n",
547 "-dn set switch statement density to `n'\n",
548 "-Dname -Dname=def define the preprocessor symbol `name'\n",
549 "-E run only the preprocessor on the named C programs and unsuffixed files\n",
550 "-g produce symbol table information for debuggers\n",
551 "-help or -? print this message\n",
552 "-Idir add `dir' to the beginning of the list of #include directories\n",
553 "-lx search library `x'\n",
554 "-N do not search the standard directories for #include files\n",
555 "-n emit code to check for dereferencing zero pointers\n",
557 "-o file leave the output in `file'\n",
558 "-P print ANSI-style declarations for globals\n",
559 "-p -pg emit profiling code; see prof(1) and gprof(1)\n",
560 "-S compile to assembly language\n",
562 "-static specify static libraries (default is dynamic)\n",
564 "-t -tname emit function tracing calls to printf or to `name'\n",
565 "-target name is ignored\n",
566 "-tempdir=dir place temporary files in `dir/'", "\n"
567 "-Uname undefine the preprocessor symbol `name'\n",
568 "-v show commands as they are executed; 2nd -v suppresses execution\n",
569 "-w suppress warnings\n",
570 "-Woarg specify system-specific `arg'\n",
571 "-W[pfal]arg pass `arg' to the preprocessor, compiler, assembler, or linker\n",
577 for (i
= 0; msgs
[i
]; i
++) {
578 fprintf(stderr
, "%s", msgs
[i
]);
579 if (strncmp("-tempdir", msgs
[i
], 8) == 0 && tempdir
)
580 fprintf(stderr
, "; default=%s", tempdir
);
582 #define xx(v) if ((s = getenv(#v))) fprintf(stderr, #v "=%s\n", s)
588 /* initinputs - if LCCINPUTS or include is defined, use them to initialize various lists */
589 static void initinputs(void) {
590 char *s
= getenv("LCCINPUTS");
593 if (s
== 0 || (s
= inputs
)[0] == 0)
596 lccinputs
= path2list(s
);
600 if (strcmp(b
->str
, ".") != 0) {
601 ilist
= append(concat("-I", b
->str
), ilist
);
602 if (strstr(com
[1], "win32") == NULL
)
603 llist
[0] = append(concat("-L", b
->str
), llist
[0]);
606 } while (b
!= lccinputs
);
610 /* interrupt - catch interrupt signals */
611 static void interrupt(int n
) {
616 /* opt - process option in arg */
617 static void opt(char *arg
) {
618 switch (arg
[1]) { /* multi-character options */
619 case 'W': /* -Wxarg */
620 if (arg
[2] && arg
[3])
627 plist
= append(&arg
[3], plist
);
630 if (strcmp(&arg
[3], "-C") || option("-b")) {
631 clist
= append(&arg
[3], clist
);
634 break; /* and fall thru */
636 alist
= append(&arg
[3], alist
);
639 llist
[0] = append(&arg
[3], llist
[0]);
642 fprintf(stderr
, "%s: %s ignored\n", progname
, arg
);
646 clist
= append(arg
, clist
);
648 case 't': /* -t -tname -tempdir=dir */
649 if (strncmp(arg
, "-tempdir=", 9) == 0)
652 clist
= append(arg
, clist
);
654 case 'p': /* -p -pg */
656 clist
= append(arg
, clist
);
658 fprintf(stderr
, "%s: %s ignored\n", progname
, arg
);
660 case 'D': /* -Dname -Dname=def */
661 case 'U': /* -Uname */
662 case 'I': /* -Idir */
663 plist
= append(arg
, plist
);
665 case 'B': /* -Bdir -Bstatic -Bdynamic */
667 if (strcmp(arg
, "-Bstatic") == 0 || strcmp(arg
, "-Bdynamic") == 0)
668 llist
[1] = append(arg
, llist
[1]);
674 error("-B overwrites earlier option", 0);
676 if (strstr(com
[1], "win32") != NULL
)
677 com
[0] = concat(replace(path
, '/', '\\'), concat("rcc", first(suffixes
[4])));
679 com
[0] = concat(path
, "rcc");
681 error("missing directory in -B option", 0);
685 if (strcmp(arg
, "-help") == 0) {
686 static int printed
= 0;
695 if (strcmp(arg
,"-static") == 0) {
697 fprintf(stderr
, "%s: %s ignored\n", progname
, arg
);
703 switch (arg
[1]) { /* single-character options */
708 fprintf(stderr
, "%s: %s ignored\n", progname
, arg
);
710 case 'A': case 'n': case 'w': case 'P':
711 clist
= append(arg
, clist
);
715 clist
= append(arg
[1] == 'g' ? "-g2" : arg
, clist
);
717 fprintf(stderr
, "%s: %s ignored\n", progname
, arg
);
721 clist
= append("-g3", clist
);
722 llist
[0] = append("-N", llist
[0]);
724 fprintf(stderr
, "%s: %s ignored\n", progname
, arg
);
733 if (strcmp(basename(cpp
[0]), "gcc-cpp") == 0)
734 plist
= append("-nostdinc", plist
);
739 if (verbose
++ == 0) {
740 if (strcmp(basename(cpp
[0]), "gcc-cpp") == 0)
741 plist
= append(arg
, plist
);
742 clist
= append(arg
, clist
);
743 fprintf(stderr
, "%s %s\n", progname
, rcsid
);
747 if (cflag
|| Sflag
|| Eflag
)
748 fprintf(stderr
, "%s: %s ignored\n", progname
, arg
);
750 llist
[1] = append(arg
, llist
[1]);
753 /* path2list - convert a colon- or semicolon-separated list to a list */
754 static List
path2list(const char *path
) {
760 if (strchr(path
, ';'))
764 if ((p
= strchr(path
, sep
))) {
765 assert(p
- path
< sizeof buf
);
766 strncpy(buf
, path
, p
- path
);
769 assert(strlen(path
) < sizeof buf
);
772 if (!find(buf
, list
))
773 list
= append(strsave(buf
), list
);
781 /* replace - copy str, then replace occurrences of from with to, return the copy */
782 char *replace(const char *str
, int from
, int to
) {
783 char *s
= strsave(str
), *p
= s
;
785 for ( ; (p
= strchr(p
, from
)) != NULL
; p
++)
790 /* rm - remove files in list */
791 static void rm(List list
) {
795 fprintf(stderr
, "rm");
798 fprintf(stderr
, " %s", b
->str
);
801 } while ((b
= b
->link
) != list
);
803 fprintf(stderr
, "\n");
807 /* strsave - return a saved copy of string str */
808 char *strsave(const char *str
) {
809 return strcpy(alloc(strlen(str
)+1), str
);
812 /* stringf - format and return a string */
813 char *stringf(const char *fmt
, ...) {
818 vsprintf(buf
, fmt
, ap
);
823 /* suffix - if one of tails[0..n-1] holds a proper suffix of name, return its index */
824 int suffix(char *name
, char *tails
[], int n
) {
825 int i
, len
= strlen(name
);
827 for (i
= 0; i
< n
; i
++) {
828 char *s
= tails
[i
], *t
;
829 for ( ; (t
= strchr(s
, ';')); s
= t
+ 1) {
831 if (len
> m
&& strncmp(&name
[len
-m
], s
, m
) == 0)
836 if (len
> m
&& strncmp(&name
[len
-m
], s
, m
) == 0)
843 /* tempname - generate a temporary file name in tempdir with given suffix */
844 char *tempname(char *suffix
) {
846 char *name
= stringf("%s/lcc%d%d%s", tempdir
, getpid(), n
++, suffix
);
848 if (strstr(com
[1], "win32") != NULL
)
849 name
= replace(name
, '/', '\\');
850 rmlist
= append(name
, rmlist
);