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
);