1 /* $NetBSD: xlint.c,v 1.3 1995/10/23 14:29:30 jpo Exp $ */
4 * Copyright (c) 1994, 1995 Jochen Pohl
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Jochen Pohl for
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * $FreeBSD: src/usr.bin/xlint/xlint/xlint.c,v 1.8 2000/01/14 09:25:31 sheldonh Exp $
34 * $DragonFly: src/usr.bin/xlint/xlint/xlint.c,v 1.8 2004/07/07 12:13:27 asmodai Exp $
37 #include <sys/param.h>
40 #include <sys/utsname.h>
52 #include "pathnames.h"
54 /* directory for temporary files */
55 static const char *tmpdir;
57 /* path name for cpp output */
60 /* files created by 1st pass */
63 /* input files for 2nd pass (without libraries) */
66 /* library which will be created by 2nd pass */
69 /* flags always passed to cpp */
70 static char **cppflags;
72 /* flags for cpp, controled by sflag/tflag */
73 static char **lcppflgs;
76 static char **l1flags;
79 static char **l2flags;
81 /* libraries for lint2 */
84 /* default libraries */
85 static char **deflibs;
87 /* additional libraries */
90 /* search path for libraries */
91 static char **libsrchpath;
94 static int iflag, oflag, Cflag, sflag, tflag, Fflag, Sflag;
96 /* print the commands executed to run the stages of compilation */
99 /* filename for oflag */
100 static char *outputfn;
102 /* reset after first .c source has been processed */
103 static int first = 1;
106 * name of a file which is currently written by a child and should
107 * be removed after abnormal termination of the child
109 static const char *currfn;
112 static void appstrg(char ***, char *);
113 static void appcstrg(char ***, const char *);
114 static void applst(char ***, char *const *);
115 static void freelst(char ***);
116 static char *concat2(const char *, const char *);
117 static char *concat3(const char *, const char *, const char *);
118 static void terminate(int);
119 static const char *basename(const char *, int);
120 static void appdef(char ***, const char *);
121 static void usage(void);
122 static void fname(const char *, int);
123 static void runchild(const char *, char *const *, const char *);
124 static void findlibs(char *const *);
125 static int rdok(const char *);
126 static void lint2(void);
127 static void cat(char *const *, const char *);
130 * Some functions to deal with lists of strings.
131 * Take care that we get no surprises in case of asyncron signals.
134 appstrg(char ***lstp, char *s)
140 for (i = 0; olst[i] != NULL; i++) ;
141 lst = xmalloc((i + 2) * sizeof (char *));
142 (void)memcpy(lst, olst, i * sizeof (char *));
149 appcstrg(char ***lstp, const char *s)
151 appstrg(lstp, xstrdup(s));
155 applst(char ***destp, char *const *src)
158 char **dest, **odest;
161 for (i = 0; odest[i] != NULL; i++) ;
162 for (k = 0; src[k] != NULL; k++) ;
163 dest = xmalloc((i + k + 1) * sizeof (char *));
164 (void)memcpy(dest, odest, i * sizeof (char *));
165 for (k = 0; src[k] != NULL; k++)
166 dest[i + k] = xstrdup(src[k]);
173 freelst(char ***lstp)
178 for (i = 0; (*lstp)[i] != NULL; i++) ;
187 concat2(const char *s1, const char *s2)
191 s = xmalloc(strlen(s1) + strlen(s2) + 1);
199 concat3(const char *s1, const char *s2, const char *s3)
203 s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
212 * Clean up after a signal.
220 (void)remove(cppout);
223 for (i = 0; p1out[i] != NULL; i++)
224 (void)remove(p1out[i]);
231 (void)remove(currfn);
233 exit(signo != 0 ? 1 : 0);
237 * Returns a pointer to the last component of strg after delim.
238 * Returns strg if the string does not contain delim.
241 basename(const char *strg, int delim)
243 const char *cp, *cp1, *cp2;
245 cp = cp1 = cp2 = strg;
246 while (*cp != '\0') {
247 if (*cp++ == delim) {
252 return (*cp1 == '\0' ? cp2 : cp1);
256 appdef(char ***lstp, const char *def)
258 appstrg(lstp, concat2("-D__", def));
259 appstrg(lstp, concat3("-D__", def, "__"));
265 (void)printf("lint [-abceghprvxzHFS] [-s|-t] [-i|-nu] [-Dname[=def]] [-Uname]\n");
266 (void)printf(" [-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile] file ...\n");
268 (void)printf("lint [-abceghprvzHFS] [-s|-t] -Clibrary [-Dname[=def]]\n");
269 (void)printf(" [-Idirectory] [-Uname] file ...\n");
274 main(int argc, char *argv[])
277 char flgbuf[3], *tmp, *s;
281 if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) {
282 tmpdir = xstrdup(_PATH_TMP);
284 s = xmalloc(len + 2);
285 (void)sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/");
289 cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX"));
290 (void)sprintf(cppout, "%slint0.XXXXXX", tmpdir);
291 if (mktemp(cppout) == NULL) {
292 warn("can't make temp");
296 p1out = xcalloc(1, sizeof (char *));
297 p2in = xcalloc(1, sizeof (char *));
298 cppflags = xcalloc(1, sizeof (char *));
299 lcppflgs = xcalloc(1, sizeof (char *));
300 l1flags = xcalloc(1, sizeof (char *));
301 l2flags = xcalloc(1, sizeof (char *));
302 l2libs = xcalloc(1, sizeof (char *));
303 deflibs = xcalloc(1, sizeof (char *));
304 libs = xcalloc(1, sizeof (char *));
305 libsrchpath = xcalloc(1, sizeof (char *));
307 appcstrg(&cppflags, "-lang-c");
308 appcstrg(&cppflags, "-$");
309 appcstrg(&cppflags, "-C");
310 appcstrg(&cppflags, "-Wcomment");
312 appcstrg(&cppflags, "-D__DragonFly__=" __XSTRING(__DragonFly__));
314 # error "This ain't NetBSD. You lose!"
315 appcstrg(&cppflags, "-D__NetBSD__");
317 appcstrg(&cppflags, "-Dlint"); /* XXX don't def. with -s */
318 appdef(&cppflags, "lint");
319 appdef(&cppflags, "unix");
321 appcstrg(&lcppflgs, "-Wtraditional");
323 if (uname(&un) == -1)
325 appdef(&cppflags, un.machine);
326 appstrg(&lcppflgs, concat2("-D", un.machine));
329 if (strcmp(un.machine, MACHINE_ARCH) != 0) {
330 appdef(&cppflags, MACHINE_ARCH);
331 appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
335 appcstrg(&deflibs, "c");
337 if (signal(SIGHUP, terminate) == SIG_IGN)
338 (void)signal(SIGHUP, SIG_IGN);
339 (void)signal(SIGINT, terminate);
340 (void)signal(SIGQUIT, terminate);
341 (void)signal(SIGTERM, terminate);
343 while (argc > optind) {
349 c = getopt(argc, argv, "abceghil:no:prstuvxzC:D:FHI:L:SU:V");
361 (void)sprintf(flgbuf, "-%c", c);
362 appcstrg(&l1flags, flgbuf);
370 (void)sprintf(flgbuf, "-%c", c);
371 appcstrg(&l1flags, flgbuf);
372 appcstrg(&l2flags, flgbuf);
386 appcstrg(&l1flags, "-p");
387 appcstrg(&l2flags, "-p");
388 if (*deflibs != NULL) {
390 appcstrg(&deflibs, "c");
398 appcstrg(&lcppflgs, "-trigraphs");
399 appcstrg(&lcppflgs, "-Wtrigraphs");
400 appcstrg(&lcppflgs, "-pedantic");
401 appcstrg(&lcppflgs, "-D__STRICT_ANSI__");
402 appcstrg(&l1flags, "-s");
403 appcstrg(&l2flags, "-s");
410 appcstrg(&l1flags, "-S");
417 appcstrg(&lcppflgs, "-traditional");
418 appstrg(&lcppflgs, concat2("-D", MACHINE));
420 appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
422 appcstrg(&l1flags, "-t");
423 appcstrg(&l2flags, "-t");
428 appcstrg(&l2flags, "-x");
432 if (Cflag || oflag || iflag)
435 appstrg(&l2flags, concat2("-C", optarg));
436 p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg));
437 (void)sprintf(p2out, "llib-l%s.ln", optarg);
444 (void)sprintf(flgbuf, "-%c", c);
445 appstrg(&cppflags, concat2(flgbuf, optarg));
449 appcstrg(&libs, optarg);
456 outputfn = xstrdup(optarg);
460 appcstrg(&libsrchpath, optarg);
464 appcstrg(&l2flags, "-H");
477 fname(argv[0], argc == 1);
491 if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0)
493 appcstrg(&libsrchpath, s);
498 (void)printf("Lint pass2:\n");
513 * Read a file name from the command line
514 * and pass it through lint1 if it is a C source.
517 fname(const char *name, int last)
519 const char *bn, *suff;
520 char **args, *ofn, *path;
523 bn = basename(name, '/');
524 suff = basename(bn, '.');
526 if (strcmp(suff, "ln") == 0) {
529 appcstrg(&p2in, name);
533 if (strcmp(suff, "c") != 0 &&
534 (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
535 warnx("unknown file type: %s\n", name);
539 if (!iflag || !first || !last)
540 (void)printf("%s:\n", Fflag ? name : bn);
542 /* build the name of the output file of lint1 */
548 ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2));
549 len = bn == suff ? strlen(bn) : (suff - 1) - bn;
550 (void)sprintf(ofn, "%.*s", (int)len, bn);
551 (void)strcat(ofn, ".ln");
553 ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX"));
554 (void)sprintf(ofn, "%slint1.XXXXXX", tmpdir);
555 if (mktemp(ofn) == NULL) {
556 warn("can't make temp");
561 appcstrg(&p1out, ofn);
563 args = xcalloc(1, sizeof (char *));
567 path = xmalloc(strlen(PATH_USRBIN) + sizeof ("/cpp"));
568 (void)sprintf(path, "%s/cpp", PATH_USRBIN);
570 appcstrg(&args, path);
571 applst(&args, cppflags);
572 applst(&args, lcppflgs);
573 appcstrg(&args, name);
574 appcstrg(&args, cppout);
576 runchild(path, args, cppout);
582 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1"));
583 (void)sprintf(path, "%s/lint1", PATH_LIBEXEC);
585 appcstrg(&args, path);
586 applst(&args, l1flags);
587 appcstrg(&args, cppout);
588 appcstrg(&args, ofn);
590 runchild(path, args, ofn);
594 appcstrg(&p2in, ofn);
601 runchild(const char *path, char *const *args, const char *crfn)
603 int status, rv, signo, i;
606 for (i = 0; args[i] != NULL; i++)
607 (void)printf("%s ", args[i]);
613 (void)fflush(stdout);
625 (void)execv(path, args);
626 warn("cannot exec %s", path);
631 while ((rv = wait(&status)) == -1 && errno == EINTR) ;
636 if (WIFSIGNALED(status)) {
637 signo = WTERMSIG(status);
638 warnx("%s got SIG%s", path, sys_signame[signo]);
641 if (WEXITSTATUS(status) != 0)
647 findlibs(char *const *liblst)
650 const char *lib, *path;
656 for (i = 0; (lib = liblst[i]) != NULL; i++) {
657 for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
658 len = strlen(path) + strlen(lib);
659 lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln"));
660 (void)sprintf(lfn, "%s/llib-l%s.ln", path, lib);
663 lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln"));
664 (void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib);
669 appstrg(&l2libs, concat2("-l", lfn));
671 warnx("cannot find llib-l%s.ln", lib);
679 rdok(const char *path)
683 if (stat(path, &sbuf) == -1)
685 if ((sbuf.st_mode & S_IFMT) != S_IFREG)
687 if (access(path, R_OK) == -1)
697 args = xcalloc(1, sizeof (char *));
699 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2"));
700 (void)sprintf(path, "%s/lint2", PATH_LIBEXEC);
702 appcstrg(&args, path);
703 applst(&args, l2flags);
704 applst(&args, l2libs);
707 runchild(path, args, p2out);
714 cat(char *const *srcs, const char *dest)
720 if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
721 warn("cannot open %s", dest);
725 buf = xmalloc(MBLKSIZ);
727 for (i = 0; (src = srcs[i]) != NULL; i++) {
728 if ((ifd = open(src, O_RDONLY)) == -1) {
730 warn("cannot open %s", src);
734 if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
736 warn("read error on %s", src);
739 if (write(ofd, buf, (size_t)rlen) == -1) {
741 warn("write error on %s", dest);
744 } while (rlen == MBLKSIZ);