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.12 2006/10/02 13:26:40 corecode 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 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 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.
223 for (i = 0; p1out[i] != NULL; i++)
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 printf("lint [-abceghprvxzHFS] [-s|-t] [-i|-nu] [-Dname[=def]] [-Uname]\n");
266 printf(" [-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile] file ...\n");
268 printf("lint [-abceghprvzHFS] [-s|-t] -Clibrary [-Dname[=def]]\n");
269 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 sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/");
289 cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX"));
290 sprintf(cppout, "%slint0.XXXXXX", tmpdir);
292 fd = mkstemp(cppout);
294 err(1, "could not make a temporary file");
300 p1out = xcalloc(1, sizeof (char *));
301 p2in = xcalloc(1, sizeof (char *));
302 cppflags = xcalloc(1, sizeof (char *));
303 lcppflgs = xcalloc(1, sizeof (char *));
304 l1flags = xcalloc(1, sizeof (char *));
305 l2flags = xcalloc(1, sizeof (char *));
306 l2libs = xcalloc(1, sizeof (char *));
307 deflibs = xcalloc(1, sizeof (char *));
308 libs = xcalloc(1, sizeof (char *));
309 libsrchpath = xcalloc(1, sizeof (char *));
311 appcstrg(&cppflags, "-x");
312 appcstrg(&cppflags, "c");
313 appcstrg(&cppflags, "-undef");
314 /* even with -undef cpp still identifies as GNUC */
315 appcstrg(&cppflags, "-U__GNUC__");
316 #if defined(__GNUC__)
318 appcstrg(&cppflags, "-$");
319 appcstrg(&cppflags, "-C");
321 appcstrg(&cppflags, "-CC");
324 appcstrg(&cppflags, "-Wcomment");
326 appcstrg(&cppflags, "-D__DragonFly__=" __XSTRING(__DragonFly__));
328 # error "This ain't NetBSD. You lose!"
329 appcstrg(&cppflags, "-D__NetBSD__");
331 appcstrg(&cppflags, "-Dlint"); /* XXX don't def. with -s */
332 appdef(&cppflags, "lint");
333 appdef(&cppflags, "unix");
335 appcstrg(&lcppflgs, "-Wtraditional");
337 if (uname(&un) == -1)
339 appdef(&cppflags, un.machine);
340 appstrg(&lcppflgs, concat2("-D", un.machine));
343 if (strcmp(un.machine, MACHINE_ARCH) != 0) {
344 appdef(&cppflags, MACHINE_ARCH);
345 appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
349 appcstrg(&deflibs, "c");
351 if (signal(SIGHUP, terminate) == SIG_IGN)
352 signal(SIGHUP, SIG_IGN);
353 signal(SIGINT, terminate);
354 signal(SIGQUIT, terminate);
355 signal(SIGTERM, terminate);
357 while (argc > optind) {
359 c = getopt(argc, argv, "abceghil:no:prstuvxzC:D:FHI:L:SU:V");
371 sprintf(flgbuf, "-%c", c);
372 appcstrg(&l1flags, flgbuf);
380 sprintf(flgbuf, "-%c", c);
381 appcstrg(&l1flags, flgbuf);
382 appcstrg(&l2flags, flgbuf);
396 appcstrg(&l1flags, "-p");
397 appcstrg(&l2flags, "-p");
398 if (*deflibs != NULL) {
400 appcstrg(&deflibs, "c");
408 appcstrg(&lcppflgs, "-trigraphs");
409 appcstrg(&lcppflgs, "-Wtrigraphs");
410 appcstrg(&lcppflgs, "-pedantic");
411 appcstrg(&lcppflgs, "-D__STRICT_ANSI__");
412 appcstrg(&l1flags, "-s");
413 appcstrg(&l2flags, "-s");
420 appcstrg(&l1flags, "-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 sprintf(p2out, "llib-l%s.ln", optarg);
454 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[optind], argc == optind + 1);
492 optreset = optind = 1;
503 if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0)
505 appcstrg(&libsrchpath, s);
510 printf("Lint pass2:\n");
525 * Read a file name from the command line
526 * and pass it through lint1 if it is a C source.
529 fname(const char *name, int last)
531 const char *bn, *suff;
532 char **args, *ofn, *path;
536 bn = basename(name, '/');
537 suff = basename(bn, '.');
539 if (strcmp(suff, "ln") == 0) {
542 appcstrg(&p2in, name);
546 if (strcmp(suff, "c") != 0 &&
547 (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
548 warnx("unknown file type: %s\n", name);
552 if (!iflag || !first || !last)
553 printf("%s:\n", Fflag ? name : bn);
555 /* build the name of the output file of lint1 */
561 ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2));
562 len = bn == suff ? strlen(bn) : (suff - 1) - bn;
563 sprintf(ofn, "%.*s", (int)len, bn);
566 ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX"));
567 sprintf(ofn, "%slint1.XXXXXX", tmpdir);
570 err(1, "could not make a temporary file");
577 appcstrg(&p1out, ofn);
579 args = xcalloc(1, sizeof (char *));
583 path = xmalloc(strlen(PATH_USRBIN) + sizeof ("/cpp"));
584 sprintf(path, "%s/cpp", PATH_USRBIN);
586 appcstrg(&args, path);
587 applst(&args, cppflags);
588 applst(&args, lcppflgs);
589 appcstrg(&args, name);
590 appcstrg(&args, cppout);
592 runchild(path, args, cppout);
598 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1"));
599 sprintf(path, "%s/lint1", PATH_LIBEXEC);
601 appcstrg(&args, path);
602 applst(&args, l1flags);
603 appcstrg(&args, cppout);
604 appcstrg(&args, ofn);
606 runchild(path, args, ofn);
610 appcstrg(&p2in, ofn);
617 runchild(const char *path, char *const *args, const char *crfn)
619 int status, rv, signo, i;
622 for (i = 0; args[i] != NULL; i++)
623 printf("%s ", args[i]);
642 warn("cannot exec %s", path);
647 while ((rv = wait(&status)) == -1 && errno == EINTR) ;
652 if (WIFSIGNALED(status)) {
653 signo = WTERMSIG(status);
654 warnx("%s got SIG%s", path, sys_signame[signo]);
657 if (WEXITSTATUS(status) != 0)
663 findlibs(char *const *liblst)
666 const char *lib, *path;
672 for (i = 0; (lib = liblst[i]) != NULL; i++) {
673 for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
674 len = strlen(path) + strlen(lib);
675 lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln"));
676 sprintf(lfn, "%s/llib-l%s.ln", path, lib);
679 lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln"));
680 sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib);
685 appstrg(&l2libs, concat2("-l", lfn));
687 warnx("cannot find llib-l%s.ln", lib);
695 rdok(const char *path)
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 sprintf(path, "%s/lint2", PATH_LIBEXEC);
718 appcstrg(&args, path);
719 applst(&args, l2flags);
720 applst(&args, l2libs);
723 runchild(path, args, p2out);
730 cat(char *const *srcs, const char *dest)
736 if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
737 warn("cannot open %s", dest);
741 buf = xmalloc(MBLKSIZ);
743 for (i = 0; (src = srcs[i]) != NULL; i++) {
744 if ((ifd = open(src, O_RDONLY)) == -1) {
746 warn("cannot open %s", src);
750 if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
752 warn("read error on %s", src);
755 if (write(ofd, buf, (size_t)rlen) == -1) {
757 warn("write error on %s", dest);
760 } while (rlen == MBLKSIZ);