1 /* $NetBSD: xlint.c,v 1.27 2002/01/31 19:09:33 tv Exp $ */
4 * Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
5 * Copyright (c) 1994, 1995 Jochen Pohl
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Jochen Pohl for
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/cdefs.h>
36 #if defined(__RCSID) && !defined(lint)
37 __RCSID("$NetBSD: xlint.c,v 1.27 2002/01/31 19:09:33 tv Exp $");
39 __FBSDID("$FreeBSD$");
41 #include <sys/param.h>
44 #include <sys/utsname.h>
56 #include "pathnames.h"
58 #define DEFAULT_PATH _PATH_DEFPATH
60 int main(int, char *[]);
62 /* directory for temporary files */
63 static const char *tmpdir;
65 /* path name for cpp output */
68 /* file descriptor for cpp output */
69 static int cppoutfd = -1;
71 /* files created by 1st pass */
74 /* input files for 2nd pass (without libraries) */
77 /* library which will be created by 2nd pass */
80 /* flags always passed to cc(1) */
83 /* flags for cc(1), controled by sflag/tflag */
84 static char **lcflags;
87 static char **l1flags;
90 static char **l2flags;
92 /* libraries for lint2 */
95 /* default libraries */
96 static char **deflibs;
98 /* additional libraries */
101 /* search path for libraries */
102 static char **libsrchpath;
104 static char *libexec_path;
107 static int iflag, oflag, Cflag, sflag, tflag, Fflag, dflag, Bflag;
109 /* print the commands executed to run the stages of compilation */
112 /* filename for oflag */
113 static char *outputfn;
115 /* reset after first .c source has been processed */
116 static int first = 1;
119 * name of a file which is currently written by a child and should
120 * be removed after abnormal termination of the child
122 static const char *currfn;
124 #if !defined(TARGET_PREFIX)
125 #define TARGET_PREFIX ""
127 static const char target_prefix[] = TARGET_PREFIX;
129 static void appstrg(char ***, char *);
130 static void appcstrg(char ***, const char *);
131 static void applst(char ***, char *const *);
132 static void freelst(char ***);
133 static char *concat2(const char *, const char *);
134 static char *concat3(const char *, const char *, const char *);
135 static void terminate(int) __attribute__((__noreturn__));
136 static const char *lbasename(const char *, int);
137 static void appdef(char ***, const char *);
138 static void usage(void);
139 static void fname(const char *);
140 static void runchild(const char *, char *const *, const char *, int);
141 static void findlibs(char *const *);
142 static int rdok(const char *);
143 static void lint2(void);
144 static void cat(char *const *, const char *);
147 * Some functions to deal with lists of strings.
148 * Take care that we get no surprises in case of asyncron signals.
151 appstrg(char ***lstp, char *s)
157 for (i = 0; olst[i] != NULL; i++)
159 lst = xrealloc(olst, (i + 2) * sizeof (char *));
166 appcstrg(char ***lstp, const char *s)
169 appstrg(lstp, xstrdup(s));
173 applst(char ***destp, char *const *src)
176 char **dest, **odest;
179 for (i = 0; odest[i] != NULL; i++)
181 for (k = 0; src[k] != NULL; k++)
183 dest = xrealloc(odest, (i + k + 1) * sizeof (char *));
184 for (k = 0; src[k] != NULL; k++)
185 dest[i + k] = xstrdup(src[k]);
191 freelst(char ***lstp)
196 for (i = 0; (*lstp)[i] != NULL; i++)
206 concat2(const char *s1, const char *s2)
210 s = xmalloc(strlen(s1) + strlen(s2) + 1);
218 concat3(const char *s1, const char *s2, const char *s3)
222 s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
231 * Clean up after a signal.
239 (void)close(cppoutfd);
241 (void)remove(cppout);
244 for (i = 0; p1out[i] != NULL; i++)
245 (void)remove(p1out[i]);
252 (void)remove(currfn);
254 exit(signo != 0 ? 1 : 0);
258 * Returns a pointer to the last component of strg after delim.
259 * Returns strg if the string does not contain delim.
262 lbasename(const char *strg, int delim)
264 const char *cp, *cp1, *cp2;
266 cp = cp1 = cp2 = strg;
267 while (*cp != '\0') {
268 if (*cp++ == delim) {
273 return (*cp1 == '\0' ? cp2 : cp1);
277 appdef(char ***lstp, const char *def)
280 appstrg(lstp, concat2("-D__", def));
281 appstrg(lstp, concat3("-D__", def, "__"));
288 (void)fprintf(stderr,
289 "usage: lint [-abceghprvwxzHF] [-s|-t] [-i|-nu] [-Dname[=def]]"
290 " [-Uname] [-X <id>[,<id>]...\n");
291 (void)fprintf(stderr,
292 "\t[-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile]"
294 (void)fprintf(stderr,
295 " lint [-abceghprvwzHF] [-s|-t] -Clibrary [-Dname[=def]]\n"
296 " [-X <id>[,<id>]...\n");
297 (void)fprintf(stderr, "\t[-Idirectory] [-Uname] [-Bpath] file"
304 main(int argc, char *argv[])
307 char flgbuf[3], *tmp, *s;
310 if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) {
311 tmpdir = xstrdup(_PATH_TMP);
313 s = xmalloc(len + 2);
314 (void)sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/");
318 cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX"));
319 (void)sprintf(cppout, "%slint0.XXXXXX", tmpdir);
320 cppoutfd = mkstemp(cppout);
321 if (cppoutfd == -1) {
322 warn("can't make temp");
326 p1out = xcalloc(1, sizeof (char *));
327 p2in = xcalloc(1, sizeof (char *));
328 cflags = xcalloc(1, sizeof (char *));
329 lcflags = xcalloc(1, sizeof (char *));
330 l1flags = xcalloc(1, sizeof (char *));
331 l2flags = xcalloc(1, sizeof (char *));
332 l2libs = xcalloc(1, sizeof (char *));
333 deflibs = xcalloc(1, sizeof (char *));
334 libs = xcalloc(1, sizeof (char *));
335 libsrchpath = xcalloc(1, sizeof (char *));
337 appcstrg(&cflags, "-E");
338 appcstrg(&cflags, "-x");
339 appcstrg(&cflags, "c");
341 appcstrg(&cflags, "-D__attribute__(x)=");
342 appcstrg(&cflags, "-D__extension__(x)=/*NOSTRICT*/0");
344 appcstrg(&cflags, "-U__GNUC__");
345 appcstrg(&cflags, "-undef");
347 appcstrg(&cflags, "-Wp,-C");
348 appcstrg(&cflags, "-Wcomment");
349 appcstrg(&cflags, "-D__LINT__");
350 appcstrg(&cflags, "-Dlint"); /* XXX don't def. with -s */
352 appdef(&cflags, "lint");
354 appcstrg(&deflibs, "c");
356 if (signal(SIGHUP, terminate) == SIG_IGN)
357 (void)signal(SIGHUP, SIG_IGN);
358 (void)signal(SIGINT, terminate);
359 (void)signal(SIGQUIT, terminate);
360 (void)signal(SIGTERM, terminate);
362 while ((c = getopt(argc, argv, "abcd:eghil:no:prstuvwxzB:C:D:FHI:L:U:VX:")) != -1) {
374 (void)sprintf(flgbuf, "-%c", c);
375 appcstrg(&l1flags, flgbuf);
383 (void)sprintf(flgbuf, "-%c", c);
384 appcstrg(&l1flags, flgbuf);
385 appcstrg(&l2flags, flgbuf);
389 (void)sprintf(flgbuf, "-%c", c);
390 appcstrg(&l1flags, flgbuf);
391 appcstrg(&l1flags, optarg);
405 appcstrg(&lcflags, "-Wtraditional");
406 appcstrg(&lcflags, "-Wno-system-headers");
407 appcstrg(&l1flags, "-p");
408 appcstrg(&l2flags, "-p");
409 if (*deflibs != NULL) {
411 appcstrg(&deflibs, "c");
419 appcstrg(&lcflags, "-trigraphs");
420 appcstrg(&lcflags, "-Wtrigraphs");
421 appcstrg(&lcflags, "-pedantic");
422 appcstrg(&lcflags, "-D__STRICT_ANSI__");
423 appcstrg(&l1flags, "-s");
424 appcstrg(&l2flags, "-s");
433 appcstrg(&lcflags, "-traditional");
434 appstrg(&lcflags, concat2("-D", MACHINE));
435 appstrg(&lcflags, concat2("-D", MACHINE_ARCH));
436 appcstrg(&l1flags, "-t");
437 appcstrg(&l2flags, "-t");
443 appcstrg(&l2flags, "-x");
447 if (Cflag || oflag || iflag)
450 appstrg(&l2flags, concat2("-C", optarg));
451 p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg));
452 (void)sprintf(p2out, "llib-l%s.ln", optarg);
460 appcstrg(&cflags, "-nostdinc");
461 appcstrg(&cflags, "-idirafter");
462 appcstrg(&cflags, optarg);
468 (void)sprintf(flgbuf, "-%c", c);
469 appstrg(&cflags, concat2(flgbuf, optarg));
473 appcstrg(&libs, optarg);
480 outputfn = xstrdup(optarg);
484 appcstrg(&libsrchpath, optarg);
488 appcstrg(&l2flags, "-H");
493 libexec_path = xstrdup(optarg);
509 * To avoid modifying getopt(3)'s state engine midstream, we
510 * explicitly accept just a few options after the first source file.
512 * In particular, only -l<lib> and -L<libdir> (and these with a space
513 * after -l or -L) are allowed.
516 const char *arg = argv[0];
536 appcstrg(list, arg + 2);
539 appcstrg(list, *++argv);
558 if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0)
560 appcstrg(&libsrchpath, s);
565 (void)printf("Lint pass2:\n");
579 * Read a file name from the command line
580 * and pass it through lint1 if it is a C source.
583 fname(const char *name)
585 const char *bn, *suff;
586 char **args, *ofn, *p, *pathname;
591 is_stdin = (strcmp(name, "-") == 0);
592 bn = lbasename(name, '/');
593 suff = lbasename(bn, '.');
595 if (strcmp(suff, "ln") == 0) {
598 appcstrg(&p2in, name);
602 if (!is_stdin && strcmp(suff, "c") != 0 &&
603 (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
604 warnx("unknown file type: %s\n", name);
608 if (!iflag || !first)
609 (void)printf("%s:\n",
610 is_stdin ? "{standard input}" : Fflag ? name : bn);
612 /* build the name of the output file of lint1 */
619 warnx("-i not supported without -o for standard input");
622 ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2));
623 len = bn == suff ? strlen(bn) : (suff - 1) - bn;
624 (void)sprintf(ofn, "%.*s", (int)len, bn);
625 (void)strcat(ofn, ".ln");
627 ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX"));
628 (void)sprintf(ofn, "%slint1.XXXXXX", tmpdir);
631 warn("can't make temp");
637 appcstrg(&p1out, ofn);
639 args = xcalloc(1, sizeof (char *));
643 if (getenv("CC") == NULL) {
644 pathname = xmalloc(strlen(PATH_USRBIN) + sizeof ("/cc"));
645 (void)sprintf(pathname, "%s/cc", PATH_USRBIN);
646 appcstrg(&args, pathname);
648 pathname = strdup(getenv("CC"));
649 for (p = strtok(pathname, " \t"); p; p = strtok(NULL, " \t"))
653 applst(&args, cflags);
654 applst(&args, lcflags);
655 appcstrg(&args, name);
657 /* we reuse the same tmp file for cpp output, so rewind and truncate */
658 if (lseek(cppoutfd, (off_t)0, SEEK_SET) != 0) {
662 if (ftruncate(cppoutfd, (off_t)0) != 0) {
667 runchild(pathname, args, cppout, cppoutfd);
674 pathname = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1") +
675 strlen(target_prefix));
676 (void)sprintf(pathname, "%s/%slint1", PATH_LIBEXEC,
680 * XXX Unclear whether we should be using target_prefix
681 * XXX here. --thorpej@wasabisystems.com
683 pathname = xmalloc(strlen(libexec_path) + sizeof ("/lint1"));
684 (void)sprintf(pathname, "%s/lint1", libexec_path);
687 appcstrg(&args, pathname);
688 applst(&args, l1flags);
689 appcstrg(&args, cppout);
690 appcstrg(&args, ofn);
692 runchild(pathname, args, ofn, -1);
696 appcstrg(&p2in, ofn);
703 runchild(const char *path, char *const *args, const char *crfn, int fdout)
705 int status, rv, signo, i;
708 for (i = 0; args[i] != NULL; i++)
709 (void)printf("%s ", args[i]);
715 (void)fflush(stdout);
728 /* setup the standard output if necessary */
730 dup2(fdout, STDOUT_FILENO);
733 (void)execvp(path, args);
734 warn("cannot exec %s", path);
739 while ((rv = wait(&status)) == -1 && errno == EINTR) ;
744 if (WIFSIGNALED(status)) {
745 signo = WTERMSIG(status);
746 #if HAVE_DECL_SYS_SIGNAME
747 warnx("%s got SIG%s", path, sys_signame[signo]);
749 warnx("%s got signal %d", path, signo);
753 if (WEXITSTATUS(status) != 0)
759 findlibs(char *const *liblst)
762 const char *lib, *path;
768 for (i = 0; (lib = liblst[i]) != NULL; i++) {
769 for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
770 len = strlen(path) + strlen(lib);
771 lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln"));
772 (void)sprintf(lfn, "%s/llib-l%s.ln", path, lib);
775 lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln"));
776 (void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib);
781 appstrg(&l2libs, concat2("-l", lfn));
783 warnx("cannot find llib-l%s.ln", lib);
791 rdok(const char *path)
795 if (stat(path, &sbuf) == -1)
797 if (!S_ISREG(sbuf.st_mode))
799 if (access(path, R_OK) == -1)
809 args = xcalloc(1, sizeof (char *));
812 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2") +
813 strlen(target_prefix));
814 (void)sprintf(path, "%s/%slint2", PATH_LIBEXEC,
818 * XXX Unclear whether we should be using target_prefix
819 * XXX here. --thorpej@wasabisystems.com
821 path = xmalloc(strlen(libexec_path) + sizeof ("/lint2"));
822 (void)sprintf(path, "%s/lint2", libexec_path);
825 appcstrg(&args, path);
826 applst(&args, l2flags);
827 applst(&args, l2libs);
830 runchild(path, args, p2out, -1);
837 cat(char *const *srcs, const char *dest)
843 if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
844 warn("cannot open %s", dest);
848 buf = xmalloc(MBLKSIZ);
850 for (i = 0; (src = srcs[i]) != NULL; i++) {
851 if ((ifd = open(src, O_RDONLY)) == -1) {
853 warn("cannot open %s", src);
857 if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
859 warn("read error on %s", src);
862 if (write(ofd, buf, (size_t)rlen) == -1) {
864 warn("write error on %s", dest);
867 } while (rlen == MBLKSIZ);