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.
35 static char rcsid[] = "$FreeBSD: src/usr.bin/xlint/xlint/xlint.c,v 1.8 2000/01/14 09:25:31 sheldonh Exp $";
38 #include <sys/param.h>
41 #include <sys/utsname.h>
53 #include "pathnames.h"
55 /* directory for temporary files */
56 static const char *tmpdir;
58 /* path name for cpp output */
61 /* files created by 1st pass */
64 /* input files for 2nd pass (without libraries) */
67 /* library which will be created by 2nd pass */
70 /* flags always passed to cpp */
71 static char **cppflags;
73 /* flags for cpp, controled by sflag/tflag */
74 static char **lcppflgs;
77 static char **l1flags;
80 static char **l2flags;
82 /* libraries for lint2 */
85 /* default libraries */
86 static char **deflibs;
88 /* additional libraries */
91 /* search path for libraries */
92 static char **libsrchpath;
95 static int iflag, oflag, Cflag, sflag, tflag, Fflag;
97 /* print the commands executed to run the stages of compilation */
100 /* filename for oflag */
101 static char *outputfn;
103 /* reset after first .c source has been processed */
104 static int first = 1;
107 * name of a file which is currently written by a child and should
108 * be removed after abnormal termination of the child
110 static const char *currfn;
113 static void appstrg __P((char ***, char *));
114 static void appcstrg __P((char ***, const char *));
115 static void applst __P((char ***, char *const *));
116 static void freelst __P((char ***));
117 static char *concat2 __P((const char *, const char *));
118 static char *concat3 __P((const char *, const char *, const char *));
119 static void terminate __P((int));
120 static const char *basename __P((const char *, int));
121 static void appdef __P((char ***, const char *));
122 static void usage __P((void));
123 static void fname __P((const char *, int));
124 static void runchild __P((const char *, char *const *, const char *));
125 static void findlibs __P((char *const *));
126 static int rdok __P((const char *));
127 static void lint2 __P((void));
128 static void cat __P((char *const *, const char *));
131 * Some functions to deal with lists of strings.
132 * Take care that we get no surprises in case of asyncron signals.
142 for (i = 0; olst[i] != NULL; i++) ;
143 lst = xmalloc((i + 2) * sizeof (char *));
144 (void)memcpy(lst, olst, i * sizeof (char *));
155 appstrg(lstp, xstrdup(s));
164 char **dest, **odest;
167 for (i = 0; odest[i] != NULL; i++) ;
168 for (k = 0; src[k] != NULL; k++) ;
169 dest = xmalloc((i + k + 1) * sizeof (char *));
170 (void)memcpy(dest, odest, i * sizeof (char *));
171 for (k = 0; src[k] != NULL; k++)
172 dest[i + k] = xstrdup(src[k]);
185 for (i = 0; (*lstp)[i] != NULL; i++) ;
199 s = xmalloc(strlen(s1) + strlen(s2) + 1);
208 const char *s1, *s2, *s3;
212 s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
221 * Clean up after a signal.
230 (void)remove(cppout);
233 for (i = 0; p1out[i] != NULL; i++)
234 (void)remove(p1out[i]);
241 (void)remove(currfn);
243 exit(signo != 0 ? 1 : 0);
247 * Returns a pointer to the last component of strg after delim.
248 * Returns strg if the string does not contain delim.
251 basename(strg, delim)
255 const char *cp, *cp1, *cp2;
257 cp = cp1 = cp2 = strg;
258 while (*cp != '\0') {
259 if (*cp++ == delim) {
264 return (*cp1 == '\0' ? cp2 : cp1);
272 appstrg(lstp, concat2("-D__", def));
273 appstrg(lstp, concat3("-D__", def, "__"));
279 (void)printf("lint [-abceghprvxzHF] [-s|-t] [-i|-nu] [-Dname[=def]] [-Uname]\n");
280 (void)printf(" [-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile] file ...\n");
282 (void)printf("lint [-abceghprvzHF] [-s|-t] -Clibrary [-Dname[=def]]\n");
283 (void)printf(" [-Idirectory] [-Uname] file ...\n");
293 char flgbuf[3], *tmp, *s;
297 if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) {
298 tmpdir = xstrdup(_PATH_TMP);
300 s = xmalloc(len + 2);
301 (void)sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/");
305 cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX"));
306 (void)sprintf(cppout, "%slint0.XXXXXX", tmpdir);
307 if (mktemp(cppout) == NULL) {
308 warn("can't make temp");
312 p1out = xcalloc(1, sizeof (char *));
313 p2in = xcalloc(1, sizeof (char *));
314 cppflags = xcalloc(1, sizeof (char *));
315 lcppflgs = xcalloc(1, sizeof (char *));
316 l1flags = xcalloc(1, sizeof (char *));
317 l2flags = xcalloc(1, sizeof (char *));
318 l2libs = xcalloc(1, sizeof (char *));
319 deflibs = xcalloc(1, sizeof (char *));
320 libs = xcalloc(1, sizeof (char *));
321 libsrchpath = xcalloc(1, sizeof (char *));
323 appcstrg(&cppflags, "-lang-c");
324 appcstrg(&cppflags, "-$");
325 appcstrg(&cppflags, "-C");
326 appcstrg(&cppflags, "-Wcomment");
328 appcstrg(&cppflags, "-D__FreeBSD__=" __XSTRING(__FreeBSD__));
330 # error "This ain't NetBSD. You lose!"
331 appcstrg(&cppflags, "-D__NetBSD__");
333 appcstrg(&cppflags, "-Dlint"); /* XXX don't def. with -s */
334 appdef(&cppflags, "lint");
335 appdef(&cppflags, "unix");
337 appcstrg(&lcppflgs, "-Wtraditional");
339 if (uname(&un) == -1)
341 appdef(&cppflags, un.machine);
342 appstrg(&lcppflgs, concat2("-D", un.machine));
345 if (strcmp(un.machine, MACHINE_ARCH) != 0) {
346 appdef(&cppflags, MACHINE_ARCH);
347 appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
351 appcstrg(&deflibs, "c");
353 if (signal(SIGHUP, terminate) == SIG_IGN)
354 (void)signal(SIGHUP, SIG_IGN);
355 (void)signal(SIGINT, terminate);
356 (void)signal(SIGQUIT, terminate);
357 (void)signal(SIGTERM, terminate);
359 while (argc > optind) {
365 c = getopt(argc, argv, "abceghil:no:prstuvxzC:D:FHI:L:U:V");
377 (void)sprintf(flgbuf, "-%c", c);
378 appcstrg(&l1flags, flgbuf);
386 (void)sprintf(flgbuf, "-%c", c);
387 appcstrg(&l1flags, flgbuf);
388 appcstrg(&l2flags, flgbuf);
402 appcstrg(&l1flags, "-p");
403 appcstrg(&l2flags, "-p");
404 if (*deflibs != NULL) {
406 appcstrg(&deflibs, "c");
414 appcstrg(&lcppflgs, "-trigraphs");
415 appcstrg(&lcppflgs, "-Wtrigraphs");
416 appcstrg(&lcppflgs, "-pedantic");
417 appcstrg(&lcppflgs, "-D__STRICT_ANSI__");
418 appcstrg(&l1flags, "-s");
419 appcstrg(&l2flags, "-s");
427 appcstrg(&lcppflgs, "-traditional");
428 appstrg(&lcppflgs, concat2("-D", MACHINE));
430 appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
432 appcstrg(&l1flags, "-t");
433 appcstrg(&l2flags, "-t");
438 appcstrg(&l2flags, "-x");
442 if (Cflag || oflag || iflag)
445 appstrg(&l2flags, concat2("-C", optarg));
446 p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg));
447 (void)sprintf(p2out, "llib-l%s.ln", optarg);
454 (void)sprintf(flgbuf, "-%c", c);
455 appstrg(&cppflags, concat2(flgbuf, optarg));
459 appcstrg(&libs, optarg);
466 outputfn = xstrdup(optarg);
470 appcstrg(&libsrchpath, optarg);
474 appcstrg(&l2flags, "-H");
487 fname(argv[0], argc == 1);
501 if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0)
503 appcstrg(&libsrchpath, s);
508 (void)printf("Lint pass2:\n");
523 * Read a file name from the command line
524 * and pass it through lint1 if it is a C source.
531 const char *bn, *suff;
532 char **args, *ofn, *path;
535 bn = basename(name, '/');
536 suff = basename(bn, '.');
538 if (strcmp(suff, "ln") == 0) {
541 appcstrg(&p2in, name);
545 if (strcmp(suff, "c") != 0 &&
546 (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
547 warnx("unknown file type: %s\n", name);
551 if (!iflag || !first || !last)
552 (void)printf("%s:\n", Fflag ? name : bn);
554 /* build the name of the output file of lint1 */
560 ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2));
561 len = bn == suff ? strlen(bn) : (suff - 1) - bn;
562 (void)sprintf(ofn, "%.*s", (int)len, bn);
563 (void)strcat(ofn, ".ln");
565 ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX"));
566 (void)sprintf(ofn, "%slint1.XXXXXX", tmpdir);
567 if (mktemp(ofn) == NULL) {
568 warn("can't make temp");
573 appcstrg(&p1out, ofn);
575 args = xcalloc(1, sizeof (char *));
579 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/cpp"));
580 (void)sprintf(path, "%s/cpp", PATH_LIBEXEC);
582 appcstrg(&args, path);
583 applst(&args, cppflags);
584 applst(&args, lcppflgs);
585 appcstrg(&args, name);
586 appcstrg(&args, cppout);
588 runchild(path, args, cppout);
594 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1"));
595 (void)sprintf(path, "%s/lint1", PATH_LIBEXEC);
597 appcstrg(&args, path);
598 applst(&args, l1flags);
599 appcstrg(&args, cppout);
600 appcstrg(&args, ofn);
602 runchild(path, args, ofn);
606 appcstrg(&p2in, ofn);
613 runchild(path, args, crfn)
614 const char *path, *crfn;
617 int status, rv, signo, i;
620 for (i = 0; args[i] != NULL; i++)
621 (void)printf("%s ", args[i]);
627 (void)fflush(stdout);
639 (void)execv(path, args);
640 warn("cannot exec %s", path);
645 while ((rv = wait(&status)) == -1 && errno == EINTR) ;
650 if (WIFSIGNALED(status)) {
651 signo = WTERMSIG(status);
652 warnx("%s got SIG%s", path, sys_signame[signo]);
655 if (WEXITSTATUS(status) != 0)
665 const char *lib, *path;
671 for (i = 0; (lib = liblst[i]) != NULL; i++) {
672 for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
673 len = strlen(path) + strlen(lib);
674 lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln"));
675 (void)sprintf(lfn, "%s/llib-l%s.ln", path, lib);
678 lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln"));
679 (void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib);
684 appstrg(&l2libs, concat2("-l", lfn));
686 warnx("cannot find llib-l%s.ln", lib);
699 if (stat(path, &sbuf) == -1)
701 if ((sbuf.st_mode & S_IFMT) != S_IFREG)
703 if (access(path, R_OK) == -1)
713 args = xcalloc(1, sizeof (char *));
715 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2"));
716 (void)sprintf(path, "%s/lint2", PATH_LIBEXEC);
718 appcstrg(&args, path);
719 applst(&args, l2flags);
720 applst(&args, l2libs);
723 runchild(path, args, p2out);
738 if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
739 warn("cannot open %s", dest);
743 buf = xmalloc(MBLKSIZ);
745 for (i = 0; (src = srcs[i]) != NULL; i++) {
746 if ((ifd = open(src, O_RDONLY)) == -1) {
748 warn("cannot open %s", src);
752 if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
754 warn("read error on %s", src);
757 if (write(ofd, buf, (size_t)rlen) == -1) {
759 warn("write error on %s", dest);
762 } while (rlen == MBLKSIZ);