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.7 2004/07/07 07:37:04 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.
141 for (i = 0; olst[i] != NULL; i++) ;
142 lst = xmalloc((i + 2) * sizeof (char *));
143 (void)memcpy(lst, olst, i * sizeof (char *));
154 appstrg(lstp, xstrdup(s));
163 char **dest, **odest;
166 for (i = 0; odest[i] != NULL; i++) ;
167 for (k = 0; src[k] != NULL; k++) ;
168 dest = xmalloc((i + k + 1) * sizeof (char *));
169 (void)memcpy(dest, odest, i * sizeof (char *));
170 for (k = 0; src[k] != NULL; k++)
171 dest[i + k] = xstrdup(src[k]);
184 for (i = 0; (*lstp)[i] != NULL; i++) ;
198 s = xmalloc(strlen(s1) + strlen(s2) + 1);
207 const char *s1, *s2, *s3;
211 s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
220 * Clean up after a signal.
229 (void)remove(cppout);
232 for (i = 0; p1out[i] != NULL; i++)
233 (void)remove(p1out[i]);
240 (void)remove(currfn);
242 exit(signo != 0 ? 1 : 0);
246 * Returns a pointer to the last component of strg after delim.
247 * Returns strg if the string does not contain delim.
250 basename(strg, delim)
254 const char *cp, *cp1, *cp2;
256 cp = cp1 = cp2 = strg;
257 while (*cp != '\0') {
258 if (*cp++ == delim) {
263 return (*cp1 == '\0' ? cp2 : cp1);
271 appstrg(lstp, concat2("-D__", def));
272 appstrg(lstp, concat3("-D__", def, "__"));
278 (void)printf("lint [-abceghprvxzHFS] [-s|-t] [-i|-nu] [-Dname[=def]] [-Uname]\n");
279 (void)printf(" [-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile] file ...\n");
281 (void)printf("lint [-abceghprvzHFS] [-s|-t] -Clibrary [-Dname[=def]]\n");
282 (void)printf(" [-Idirectory] [-Uname] file ...\n");
292 char flgbuf[3], *tmp, *s;
296 if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) {
297 tmpdir = xstrdup(_PATH_TMP);
299 s = xmalloc(len + 2);
300 (void)sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/");
304 cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX"));
305 (void)sprintf(cppout, "%slint0.XXXXXX", tmpdir);
306 if (mktemp(cppout) == NULL) {
307 warn("can't make temp");
311 p1out = xcalloc(1, sizeof (char *));
312 p2in = xcalloc(1, sizeof (char *));
313 cppflags = xcalloc(1, sizeof (char *));
314 lcppflgs = xcalloc(1, sizeof (char *));
315 l1flags = xcalloc(1, sizeof (char *));
316 l2flags = xcalloc(1, sizeof (char *));
317 l2libs = xcalloc(1, sizeof (char *));
318 deflibs = xcalloc(1, sizeof (char *));
319 libs = xcalloc(1, sizeof (char *));
320 libsrchpath = xcalloc(1, sizeof (char *));
322 appcstrg(&cppflags, "-lang-c");
323 appcstrg(&cppflags, "-$");
324 appcstrg(&cppflags, "-C");
325 appcstrg(&cppflags, "-Wcomment");
327 appcstrg(&cppflags, "-D__DragonFly__=" __XSTRING(__DragonFly__));
329 # error "This ain't NetBSD. You lose!"
330 appcstrg(&cppflags, "-D__NetBSD__");
332 appcstrg(&cppflags, "-Dlint"); /* XXX don't def. with -s */
333 appdef(&cppflags, "lint");
334 appdef(&cppflags, "unix");
336 appcstrg(&lcppflgs, "-Wtraditional");
338 if (uname(&un) == -1)
340 appdef(&cppflags, un.machine);
341 appstrg(&lcppflgs, concat2("-D", un.machine));
344 if (strcmp(un.machine, MACHINE_ARCH) != 0) {
345 appdef(&cppflags, MACHINE_ARCH);
346 appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
350 appcstrg(&deflibs, "c");
352 if (signal(SIGHUP, terminate) == SIG_IGN)
353 (void)signal(SIGHUP, SIG_IGN);
354 (void)signal(SIGINT, terminate);
355 (void)signal(SIGQUIT, terminate);
356 (void)signal(SIGTERM, terminate);
358 while (argc > optind) {
364 c = getopt(argc, argv, "abceghil:no:prstuvxzC:D:FHI:L:SU:V");
376 (void)sprintf(flgbuf, "-%c", c);
377 appcstrg(&l1flags, flgbuf);
385 (void)sprintf(flgbuf, "-%c", c);
386 appcstrg(&l1flags, flgbuf);
387 appcstrg(&l2flags, flgbuf);
401 appcstrg(&l1flags, "-p");
402 appcstrg(&l2flags, "-p");
403 if (*deflibs != NULL) {
405 appcstrg(&deflibs, "c");
413 appcstrg(&lcppflgs, "-trigraphs");
414 appcstrg(&lcppflgs, "-Wtrigraphs");
415 appcstrg(&lcppflgs, "-pedantic");
416 appcstrg(&lcppflgs, "-D__STRICT_ANSI__");
417 appcstrg(&l1flags, "-s");
418 appcstrg(&l2flags, "-s");
425 appcstrg(&l1flags, "-S");
432 appcstrg(&lcppflgs, "-traditional");
433 appstrg(&lcppflgs, concat2("-D", MACHINE));
435 appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
437 appcstrg(&l1flags, "-t");
438 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);
459 (void)sprintf(flgbuf, "-%c", c);
460 appstrg(&cppflags, concat2(flgbuf, optarg));
464 appcstrg(&libs, optarg);
471 outputfn = xstrdup(optarg);
475 appcstrg(&libsrchpath, optarg);
479 appcstrg(&l2flags, "-H");
492 fname(argv[0], argc == 1);
506 if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0)
508 appcstrg(&libsrchpath, s);
513 (void)printf("Lint pass2:\n");
528 * Read a file name from the command line
529 * and pass it through lint1 if it is a C source.
536 const char *bn, *suff;
537 char **args, *ofn, *path;
540 bn = basename(name, '/');
541 suff = basename(bn, '.');
543 if (strcmp(suff, "ln") == 0) {
546 appcstrg(&p2in, name);
550 if (strcmp(suff, "c") != 0 &&
551 (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
552 warnx("unknown file type: %s\n", name);
556 if (!iflag || !first || !last)
557 (void)printf("%s:\n", Fflag ? name : bn);
559 /* build the name of the output file of lint1 */
565 ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2));
566 len = bn == suff ? strlen(bn) : (suff - 1) - bn;
567 (void)sprintf(ofn, "%.*s", (int)len, bn);
568 (void)strcat(ofn, ".ln");
570 ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX"));
571 (void)sprintf(ofn, "%slint1.XXXXXX", tmpdir);
572 if (mktemp(ofn) == NULL) {
573 warn("can't make temp");
578 appcstrg(&p1out, ofn);
580 args = xcalloc(1, sizeof (char *));
584 path = xmalloc(strlen(PATH_USRBIN) + sizeof ("/cpp"));
585 (void)sprintf(path, "%s/cpp", PATH_USRBIN);
587 appcstrg(&args, path);
588 applst(&args, cppflags);
589 applst(&args, lcppflgs);
590 appcstrg(&args, name);
591 appcstrg(&args, cppout);
593 runchild(path, args, cppout);
599 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1"));
600 (void)sprintf(path, "%s/lint1", PATH_LIBEXEC);
602 appcstrg(&args, path);
603 applst(&args, l1flags);
604 appcstrg(&args, cppout);
605 appcstrg(&args, ofn);
607 runchild(path, args, ofn);
611 appcstrg(&p2in, ofn);
618 runchild(path, args, crfn)
619 const char *path, *crfn;
622 int status, rv, signo, i;
625 for (i = 0; args[i] != NULL; i++)
626 (void)printf("%s ", args[i]);
632 (void)fflush(stdout);
644 (void)execv(path, args);
645 warn("cannot exec %s", path);
650 while ((rv = wait(&status)) == -1 && errno == EINTR) ;
655 if (WIFSIGNALED(status)) {
656 signo = WTERMSIG(status);
657 warnx("%s got SIG%s", path, sys_signame[signo]);
660 if (WEXITSTATUS(status) != 0)
670 const char *lib, *path;
676 for (i = 0; (lib = liblst[i]) != NULL; i++) {
677 for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
678 len = strlen(path) + strlen(lib);
679 lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln"));
680 (void)sprintf(lfn, "%s/llib-l%s.ln", path, lib);
683 lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln"));
684 (void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib);
689 appstrg(&l2libs, concat2("-l", lfn));
691 warnx("cannot find llib-l%s.ln", lib);
704 if (stat(path, &sbuf) == -1)
706 if ((sbuf.st_mode & S_IFMT) != S_IFREG)
708 if (access(path, R_OK) == -1)
718 args = xcalloc(1, sizeof (char *));
720 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2"));
721 (void)sprintf(path, "%s/lint2", PATH_LIBEXEC);
723 appcstrg(&args, path);
724 applst(&args, l2flags);
725 applst(&args, l2libs);
728 runchild(path, args, p2out);
743 if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
744 warn("cannot open %s", dest);
748 buf = xmalloc(MBLKSIZ);
750 for (i = 0; (src = srcs[i]) != NULL; i++) {
751 if ((ifd = open(src, O_RDONLY)) == -1) {
753 warn("cannot open %s", src);
757 if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
759 warn("read error on %s", src);
762 if (write(ofd, buf, (size_t)rlen) == -1) {
764 warn("write error on %s", dest);
767 } while (rlen == MBLKSIZ);