diff options
author | joerg <joerg@FreeBSD.org> | 1995-11-05 15:56:42 +0000 |
---|---|---|
committer | joerg <joerg@FreeBSD.org> | 1995-11-05 15:56:42 +0000 |
commit | 97ea65b2cb83e7b5b2c4afcacc3a185482457c2a (patch) | |
tree | e48ecf34ec80fd6977218c2852e4419794cc64d7 /usr.bin/xlint/xlint | |
download | FreeBSD-src-97ea65b2cb83e7b5b2c4afcacc3a185482457c2a.zip FreeBSD-src-97ea65b2cb83e7b5b2c4afcacc3a185482457c2a.tar.gz |
Jochen Pohl's lint(1) from NetBSD. Yet another import.
This is just a vendor import by now. I'll wait until i'll get the
imported files back via CTM before applying the FreeBSD patches.
Don't use it yet.
Submitted by: Jochen Pohl <jpo.drs@sni.de>
Obtained from: (NetBSD -- this version is directly from Jochen)
Diffstat (limited to 'usr.bin/xlint/xlint')
-rw-r--r-- | usr.bin/xlint/xlint/Makefile | 17 | ||||
-rw-r--r-- | usr.bin/xlint/xlint/lint.1 | 509 | ||||
-rw-r--r-- | usr.bin/xlint/xlint/pathnames.h | 38 | ||||
-rw-r--r-- | usr.bin/xlint/xlint/xlint.c | 761 |
4 files changed, 1325 insertions, 0 deletions
diff --git a/usr.bin/xlint/xlint/Makefile b/usr.bin/xlint/xlint/Makefile new file mode 100644 index 0000000..41c833c --- /dev/null +++ b/usr.bin/xlint/xlint/Makefile @@ -0,0 +1,17 @@ +# $NetBSD: Makefile,v 1.2 1995/07/03 21:25:14 cgd Exp $ + +.PATH: ${.CURDIR}/../lint1 + +PROG= xlint +SRCS= xlint.c mem.c +MAN= lint.1 + +CFLAGS+=-I${.CURDIR}/../lint1 + +realinstall: + install ${COPY} ${STRIP} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${PROG} ${DESTDIR}${BINDIR}/lint + + +.include "${.CURDIR}/../../Makefile.inc" +.include <bsd.prog.mk> diff --git a/usr.bin/xlint/xlint/lint.1 b/usr.bin/xlint/xlint/lint.1 new file mode 100644 index 0000000..99d459c --- /dev/null +++ b/usr.bin/xlint/xlint/lint.1 @@ -0,0 +1,509 @@ +.\" $NetBSD: lint.1,v 1.3 1995/10/23 13:45:31 jpo Exp $ +.\" +.\" Copyright (c) 1994, 1995 Jochen Pohl +.\" All Rights Reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by Jochen Pohl for +.\" The NetBSD Project. +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd August 28, 1994 +.Dt LINT 1 +.Os NetBSD +.Sh NAME +.Nm lint +.Nd a C program verifier. +.Sh SYNOPSIS +.Nm lint +.Op Fl abceghprvxzHFV +.Op Fl s Ns | Ns Fl t +.Op Fl i Ns | Ns Fl nu +.Op Fl D Ns Ar name Ns Op =def +.Op Fl U Ns Ar name +.Op Fl I Ns Ar directory +.Op Fl L Ns Ar directory +.Op Fl l Ns Ar library +.Op Fl o Ns Ar outputfile +.Ar +.Nm lint +.Op Fl abceghprvzHFV +.Op Fl s Ns | Ns Fl t +.Fl C Ns Ar library +.Op Fl D Ns Ar name Ns Op =def +.Op Fl I Ns Ar directory +.Op Fl U Ns Ar name +.Ar +.Sh DESCRIPTION +.Nm +attempts to detect features of the named C program files +that are likely to be bugs, to be non-portable, or to be +wasteful. It also performs stricter type checking then does +the C compiler. +.Nm +runs the C preprocessor as its first phase, with the +preprocessor symbol +.Sy lint +defined to allow certain questionable code to be altered +or skipped by +.Nm lint . +Therefore, this symbol should be thought of as a reserved +word for all code that is to be checked by +.Nm lint . +.Pp +Among the possible problems that are currently noted are +unreachable statements, loops not entered at the top, +variables declared and not used, and logical expressions +with constant values. Function calls are checked for +inconsistencies, such as calls to functions that return +values in some places and not in others, functions called +with varying numbers of arguments, function calls that +pass arguments of a type other than the type the function +expects to receive, functions whose values are not used, +and calls to functions not returning values that use +the non-existent return value of the function. +.Pp +Filename arguments ending with +.Pa \&.c +are taken to be C source files. Filename arguments with +names ending with +.Pa \&.ln +are taken to be the result of an earlier invocation of +.Nm lint , +with either the +.Fl i , +.Fl o +or +.Fl C +option in effect. The +.Pa \&.ln +files are analogous to the +.Pa \&.o +(object) files produced by +.Xr cc 1 +from +.Pa \&.c +files. +.Nm +also accepts special libraries specified with the +.Fl l +option, which contain definitions of library routines and +variables. +.Pp +.Nm +takes all the +.Pa \&.c , \&.ln , +and +.Pa llib-l Ns Ar library Ns Pa \&.ln +(lint library) files and processes them in command-line order. +By default, +.Nm +appends the standard C lint library +.Pq Pa llib-lc.ln +to the end of the list of files. When the +.Fl i +option is used, the +.Pa \&.ln +files are ignored. +Also, when the +.Fl o +or +.Fl i +options are used, the +.Pa llib-l Ns Ar library Ns Pa \&.ln +files are ignored. When the +.Fl i +option is +.Em omitted +the second pass of +.Nm +checks this list of files for mutual compatibility. At this point, +if a complaint stems not from a given source file, but from one of +its included files, the source filename will be printed followed by +a question mark. +.Pp +.Sy Options +.Bl -tag -width Fl +.It Fl a +Report assignments of +.Sy long +values to variables that are not +.Sy long . +.It Fl aa +Additional to +.Fl a , +report +.Em all +assignments of integer values to other integer values which +cause implicit narrowing conversion. +.It Fl b +Report +.Sy break +statements that cannot be reached. This is not the default +because, unfortunately, most +.Xr lex 1 +and many +.Xr yacc 1 +outputs produce many such complaints. +.It Fl c +Complain about casts which have questionable portability. +.It Fl e +Complain about unusual operations on +.Sy enum Ns -Types +and combinations of +.Sy enum Ns - +and +.Sy integer Ns -Types. +.It Fl g +Don't print warnings for some extensions of +.Xr gcc 1 +to the C language. Currently these are nonconstant initializers in +automatic aggregate initializations, arithmetic on pointer to void, +zero sized structures, subscripting of non-lvalue arrays, prototypes +overriding old style function declarations and long long +integer types. The +.Fl g +flag also turns on the keywords +.Sy asm +and +.Sy inline +(alternate keywords with leading underscores for both +.Sy asm +and +.Sy inline +are always available). +.It Fl h +Apply a number of heuristic tests to attempt to intuit +bugs, improve style, and reduce waste. +.It Fl i +Produce a +.Pa \&.ln +file for every +.Pa \&.c +file on the command line. These +.Pa \&.ln +files are the product of +.Nm lint Ns 's +first pass only, and are not checked for compatibility +between functions. +.It Fl n +Do not check compatibility against the standard library. +.It Fl p +Attempt to check portability of code to other dialects of C. +.It Fl r +In case of redeclarations report the position of the +previous declaration. +.It Fl s +Strict ANSI C mode. Issue warnings and errors required by ANSI C. +Also do not produce warnings for constructs which behave +differently in traditional C and ANSI C. With the +.Fl s +flag, +.Li __STRICT_ANSI__ +is a predefined preprocessor macro. +.It Fl t +Traditional C mode. +.Li __STDC__ +is not predefined in this mode. Warnings are printed for constructs +not allowed in traditional C. Warnings for constructs which behave +differently in traditional C and ANSI C are suppressed. Preprocessor +macros describing the machine type (e.g. +.Li sun3 Ns ) +and machine architecture (e.g. +.Li m68k Ns ) +are defined without leading and trailing underscores. The keywords +.Sy const Ns , +.Sy volatile +and +.Sy signed +are not available in traditional C mode (although the alternate +keywords with leading underscores still are). +.It Fl u +Do not complain about functions and external variables used +and not defined, or defined and not used (this is suitable +for running +.Nm +on a subset of files comprising part of a larger program). +.It Fl v +Suppress complaints about unused arguments in functions. +.It Fl x +Report variables refferd to by +.Sy extern +declarations, but never used. +.It Fl z +Do not complain about structures that are never defined +(for example, using a structure pointer without knowing +its contents). +.It Fl C Ns Ar library +Create a +.Nm +library with the name +.Pa llib-l Ns Ar library Ns Pa .ln . +This library is built from all +.Pa \&.c +and +.Pa \&.ln +input files. After all global definitions of functions and +variables in these files are written to the newly created library, +.Nm +checks all input files, including libraries specified with the +.Fl l +option, for mutual compatibility. +.It Fl D Ns Ar name Ns Op =def +Define +.Ar name +for +.Xr cpp 1 , +as if by a +.Li #define +directive. If no definition is given, +.Ar name +is defined as 1. +.It Fl I Ns Ar directory +Add +.Ar directory +to the list of directories in which to search for include files. +.It Fl l Ns Ar library +Include the lint library +.Pa llib-l Ns Ar library Ns Pa \&.ln . +.It Fl L Ns Ar directory +Search for lint libraries in +.Ar directory +and +.Ar directory Ns Pa /lint +before searching the standard place. +.It Fl F +Print pathnames of files. +.Nm +normally prints the filename without the path. +.It Fl H +If a complaint stems from an included file +.Nm +prints the name of the included file instead of the source file name +followed by a question mark. +.It Fl o Ns Ar outputfile +Name the output file +.Ar outputfile . +The output file produced is the input that is given to +.Nm lint Ns 's +second pass. The +.Fl o +option simply saves this file in the named output file. If the +.Fl i +option is also used the files are not checked for compatibility. +To produce a +.Pa llib-l Ns Ar library Ns Pa \&.ln +without extraneous messages, use of the +.Fl u +option is suggested. The +.Fl v +option is useful if the source file(s) for the lint library +are just external interfaces. +.It Fl U Ns Ar name +Remove any initial definition of +.Ar name +for the preprocessor. +.It Fl V +Print the command lines constructed by the controller program to +run the C preprocessor and +.Nm lint Ns 's +first and second pass. +.El +.Pp +.Sy Input Grammar +.Pp +.Nm lint Ns 's +first pass reads standard C source files. +.Nm +recognizes the following C comments as commands. +.Bl -tag -width Fl +.It Li /* ARGSUSED Ns Ar n Li */ +makes +.Nm +check only the first +.Ar n +arguments for usage; a missing +.Ar n +is taken to be 0 (this option acts like the +.Fl v +option for the next function). +.It Li /* CONSTCOND */ No or Xo +.Li /* CONSTANTCOND */ No or +.Li /* CONSTANTCONDITION */ +.Xc +suppress complaints about constant operands for the next expression. +.It Li /*\ FALLTHRU\ */ No or Xo +.Li /* FALLTHROUGH */ +.Xc +suppress complaints about fall through to a +.Sy case +or +.Sy default +labelled statement. This directive should be placed immediately +preceding the label. +.It Li /* LINTLIBRARY */ +At the beginning of a file, mark all functions and variables defined +in this file as +.Em used . +Also shut off complaints about unused function arguments. +.It Li /* LINTED Xo +.Op Ar comment +.Li */ No or +.Li /* NOSTRICT +.Op Ar comment +.Li */ +.Xc +Suppresses any intra-file warning except those dealing with +unused variables or functions. This directive should be placed +on the line immediately preceding where the lint warning occured. +.It Li /* LONGLONG */ +Suppress complaints about use of long long integer types. +.It Li /* NOTREACHED */ +At appropriate points, inhibit complaints about unreachable code. +(This comment is typically placed just after calls to functions +like +.Xr exit 2 ). +.It Li /* PRINTFLIKE Ns Ar n Li */ +makes +.Nm +check the first +.Pq Ar n Ns No -1 +arguments as usual. The +.Ar n Ns No -th +argument is interpreted as a +.Sy printf +format string that is used to check the remaining arguments. +.It Li /* PROTOLIB Ns Ar n Li */ +causes +.Nm +to treat function declaration prototypes as function definitions +if +.Ar n +is non-zero. This directive can only be used in conjunction with +the +.Li /* LINTLIBRARY */ +directive. If +.Ar n +is zero, function prototypes will be treated normally. +.It Li /* SCANFLIKE Ns Ar n Li */ +makes +.Nm +check the first +.Pq Ar n Ns No -1 +arguments as usual. The +.Ar n Ns No -th +argument is interpreted as a +.Sy scanf +format string that is used to check the remaining arguments. +.It Li /* VARARGS Ns Ar n Li */ +Suppress the usual checking for variable numbers of arguments in +the following function declaration. The data types of the first +.Ar n +arguments are checked; a missing +.Ar n +is taken to be 0. +.El +.Pp +The behavior of the +.Fl i +and the +.Fl o +options allows for incremental use of +.Nm +on a set of C source files. Generally, one invokes +.Nm +once for each source file with the +.Fl i +option. Each of these invocations produces a +.Pa \&.ln +file that corresponds to the +.Pa \&.c +file, and prints all messages that are about just that +source file. After all the source files have been separetely +run through +.Nm lint , +it is invoked once more (without the +.Fl i +option), listing all the +.Pa \&.ln +files with the needed +.Fl l Ns Ar library +options. this will print all the inter-file inconsistencies. This +scheme works well with +.Xr make 1 ; +it allows +.Xr make 1 +to be used to +.Nm +only the source files that have been modified since the last +time the set of source files were +.Nm lint Ns No ed . +.Sh ENVIRONMENT +.Bl -tag -width Fl +.It Ev LIBDIR +the directory where the lint libraries specified by the +.Fl l Ns Ar library +option must exist. If this environment variable is undefined, +then the default path +.Pa /usr/libdata/lint +will be used to search for the libraries. +.It Ev TMPDIR +usually the path for temporary files can be redefined by setting +this environment variable. +.El +.Sh FILES +.Bl -tag -width /usr/libdata/lint/llib-lc.ln -compact +.It Pa /usr/libexec/lint Ns Bq 12 +programs +.It Pa /usr/libdata/lint/llib-l*.ln +various prebuilt lint libraries +.It Pa /tmp/lint* +temporaries +.Sh SEE ALSO +.Xr cc 1 , +.Xr cpp 1 , +.Xr make 1 +.Sh AUTHORS +Jochen Pohl +.Sh BUGS +The routines +.Xr exit 2 , +.Xr longjmp 3 +and other functions that do not return are not understood; this +causes various incorrect diagnostics. +.Pp +Static functions which are used only before their first +extern declaration are reported as unused. +.Pp +Libraries created by the +.Fl o +option will, when used in later +.Nm +runs, cause certain errors that were reported when the libraries +were created to be reported again, and cause line numbers and file +names from the original source used to create those libraries +to be reported in error messages. For these reasons, it is recommended +to use the +.Fl C +option to create lint libraries. diff --git a/usr.bin/xlint/xlint/pathnames.h b/usr.bin/xlint/xlint/pathnames.h new file mode 100644 index 0000000..d03845d --- /dev/null +++ b/usr.bin/xlint/xlint/pathnames.h @@ -0,0 +1,38 @@ +/* $NetBSD: pathnames.h,v 1.2 1995/07/03 21:25:20 cgd Exp $ */ + +/* + * Copyright (c) 1994, 1995 Jochen Pohl + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Jochen Pohl for + * The NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* directory where lint1 and lint2 reside */ +#define PATH_LIBEXEC "/usr/libexec" + +/* default library search path */ +#define PATH_LINTLIB "/usr/libdata/lint" diff --git a/usr.bin/xlint/xlint/xlint.c b/usr.bin/xlint/xlint/xlint.c new file mode 100644 index 0000000..3e57797 --- /dev/null +++ b/usr.bin/xlint/xlint/xlint.c @@ -0,0 +1,761 @@ +/* $NetBSD: xlint.c,v 1.3 1995/10/23 14:29:30 jpo Exp $ */ + +/* + * Copyright (c) 1994, 1995 Jochen Pohl + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Jochen Pohl for + * The NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef lint +static char rcsid[] = "$NetBSD: xlint.c,v 1.3 1995/10/23 14:29:30 jpo Exp $"; +#endif + +#include <sys/param.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <sys/utsname.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <err.h> +#include <errno.h> +#include <paths.h> + +#include "lint.h" +#include "pathnames.h" + +/* directory for temporary files */ +static const char *tmpdir; + +/* path name for cpp output */ +static char *cppout; + +/* files created by 1st pass */ +static char **p1out; + +/* input files for 2nd pass (without libraries) */ +static char **p2in; + +/* library which will be created by 2nd pass */ +static char *p2out; + +/* flags always passed to cpp */ +static char **cppflags; + +/* flags for cpp, controled by sflag/tflag */ +static char **lcppflgs; + +/* flags for lint1 */ +static char **l1flags; + +/* flags for lint2 */ +static char **l2flags; + +/* libraries for lint2 */ +static char **l2libs; + +/* default libraries */ +static char **deflibs; + +/* additional libraries */ +static char **libs; + +/* search path for libraries */ +static char **libsrchpath; + +/* flags */ +static int iflag, oflag, Cflag, sflag, tflag, Fflag; + +/* print the commands executed to run the stages of compilation */ +static int Vflag; + +/* filename for oflag */ +static char *outputfn; + +/* reset after first .c source has been processed */ +static int first = 1; + +/* + * name of a file which is currently written by a child and should + * be removed after abnormal termination of the child + */ +static const char *currfn; + + +static void appstrg __P((char ***, char *)); +static void appcstrg __P((char ***, const char *)); +static void applst __P((char ***, char *const *)); +static void freelst __P((char ***)); +static char *concat2 __P((const char *, const char *)); +static char *concat3 __P((const char *, const char *, const char *)); +static void terminate __P((int)); +static const char *basename __P((const char *, int)); +static void appdef __P((char ***, const char *)); +static void usage __P((void)); +static void fname __P((const char *, int)); +static void runchild __P((const char *, char *const *, const char *)); +static void findlibs __P((char *const *)); +static int rdok __P((const char *)); +static void lint2 __P((void)); +static void cat __P((char *const *, const char *)); + +/* + * Some functions to deal with lists of strings. + * Take care that we get no surprises in case of asyncron signals. + */ +static void +appstrg(lstp, s) + char ***lstp, *s; +{ + char **lst, **olst; + int i; + + olst = *lstp; + for (i = 0; olst[i] != NULL; i++) ; + lst = xmalloc((i + 2) * sizeof (char *)); + (void)memcpy(lst, olst, i * sizeof (char *)); + lst[i] = s; + lst[i + 1] = NULL; + *lstp = lst; +} + +static void +appcstrg(lstp, s) + char ***lstp; + const char *s; +{ + appstrg(lstp, xstrdup(s)); +} + +static void +applst(destp, src) + char ***destp; + char *const *src; +{ + int i, k; + char **dest, **odest; + + odest = *destp; + for (i = 0; odest[i] != NULL; i++) ; + for (k = 0; src[k] != NULL; k++) ; + dest = xmalloc((i + k + 1) * sizeof (char *)); + (void)memcpy(dest, odest, i * sizeof (char *)); + for (k = 0; src[k] != NULL; k++) + dest[i + k] = xstrdup(src[k]); + dest[i + k] = NULL; + *destp = dest; + free(odest); +} + +static void +freelst(lstp) + char ***lstp; +{ + char *s; + int i; + + for (i = 0; (*lstp)[i] != NULL; i++) ; + while (i-- > 0) { + s = (*lstp)[i]; + (*lstp)[i] = NULL; + free(s); + } +} + +static char * +concat2(s1, s2) + const char *s1, *s2; +{ + char *s; + + s = xmalloc(strlen(s1) + strlen(s2) + 1); + (void)strcpy(s, s1); + (void)strcat(s, s2); + + return (s); +} + +static char * +concat3(s1, s2, s3) + const char *s1, *s2, *s3; +{ + char *s; + + s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1); + (void)strcpy(s, s1); + (void)strcat(s, s2); + (void)strcat(s, s3); + + return (s); +} + +/* + * Clean up after a signal. + */ +static void +terminate(signo) + int signo; +{ + int i; + + if (cppout != NULL) + (void)remove(cppout); + + if (p1out != NULL) { + for (i = 0; p1out[i] != NULL; i++) + (void)remove(p1out[i]); + } + + if (p2out != NULL) + (void)remove(p2out); + + if (currfn != NULL) + (void)remove(currfn); + + exit(signo != 0 ? 1 : 0); +} + +/* + * Returns a pointer to the last component of strg after delim. + * Returns strg if the string does not contain delim. + */ +static const char * +basename(strg, delim) + const char *strg; + int delim; +{ + const char *cp, *cp1, *cp2; + + cp = cp1 = cp2 = strg; + while (*cp != '\0') { + if (*cp++ == delim) { + cp2 = cp1; + cp1 = cp; + } + } + return (*cp1 == '\0' ? cp2 : cp1); +} + +static void +appdef(lstp, def) + char ***lstp; + const char *def; +{ + appstrg(lstp, concat2("-D__", def)); + appstrg(lstp, concat3("-D__", def, "__")); +} + +static void +usage() +{ + (void)printf("lint [-abceghprvxzHF] [-s|-t] [-i|-nu] [-Dname[=def]] [-Uname]\n"); + (void)printf(" [-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile] file ...\n"); + (void)printf("\n"); + (void)printf("lint [-abceghprvzHF] [-s|-t] -Clibrary [-Dname[=def]]\n"); + (void)printf(" [-Idirectory] [-Uname] file ...\n"); + terminate(-1); +} + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int c; + char flgbuf[3], *tmp, *s; + size_t len; + struct utsname un; + + if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) { + tmpdir = xstrdup(_PATH_TMP); + } else { + s = xmalloc(len + 2); + (void)sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/"); + tmpdir = s; + } + + cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX")); + (void)sprintf(cppout, "%slint0.XXXXXX", tmpdir); + if (mktemp(cppout) == NULL) { + warn("can't make temp"); + terminate(-1); + } + + p1out = xcalloc(1, sizeof (char *)); + p2in = xcalloc(1, sizeof (char *)); + cppflags = xcalloc(1, sizeof (char *)); + lcppflgs = xcalloc(1, sizeof (char *)); + l1flags = xcalloc(1, sizeof (char *)); + l2flags = xcalloc(1, sizeof (char *)); + l2libs = xcalloc(1, sizeof (char *)); + deflibs = xcalloc(1, sizeof (char *)); + libs = xcalloc(1, sizeof (char *)); + libsrchpath = xcalloc(1, sizeof (char *)); + + appcstrg(&cppflags, "-lang-c"); + appcstrg(&cppflags, "-undef"); + appcstrg(&cppflags, "-$"); + appcstrg(&cppflags, "-C"); + appcstrg(&cppflags, "-Wcomment"); + appcstrg(&cppflags, "-D__NetBSD__"); + appcstrg(&cppflags, "-Dlint"); /* XXX don't def. with -s */ + appdef(&cppflags, "lint"); + appdef(&cppflags, "unix"); + + appcstrg(&lcppflgs, "-Wtraditional"); + + if (uname(&un) == -1) + err(1, "uname"); + appdef(&cppflags, un.machine); + appstrg(&lcppflgs, concat2("-D", un.machine)); + +#ifdef MACHINE_ARCH + if (strcmp(un.machine, MACHINE_ARCH) != 0) { + appdef(&cppflags, MACHINE_ARCH); + appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH)); + } +#endif + + appcstrg(&deflibs, "c"); + + if (signal(SIGHUP, terminate) == SIG_IGN) + (void)signal(SIGHUP, SIG_IGN); + (void)signal(SIGINT, terminate); + (void)signal(SIGQUIT, terminate); + (void)signal(SIGTERM, terminate); + + while (argc > optind) { + + argc -= optind; + argv += optind; + optind = 0; + + c = getopt(argc, argv, "abceghil:no:prstuvxzC:D:FHI:L:U:V"); + + switch (c) { + + case 'a': + case 'b': + case 'c': + case 'e': + case 'g': + case 'r': + case 'v': + case 'z': + (void)sprintf(flgbuf, "-%c", c); + appcstrg(&l1flags, flgbuf); + break; + + case 'F': + Fflag = 1; + /* FALLTHROUGH */ + case 'u': + case 'h': + (void)sprintf(flgbuf, "-%c", c); + appcstrg(&l1flags, flgbuf); + appcstrg(&l2flags, flgbuf); + break; + + case 'i': + if (Cflag) + usage(); + iflag = 1; + break; + + case 'n': + freelst(&deflibs); + break; + + case 'p': + appcstrg(&l1flags, "-p"); + appcstrg(&l2flags, "-p"); + if (*deflibs != NULL) { + freelst(&deflibs); + appcstrg(&deflibs, "c"); + } + break; + + case 's': + if (tflag) + usage(); + freelst(&lcppflgs); + appcstrg(&lcppflgs, "-trigraphs"); + appcstrg(&lcppflgs, "-Wtrigraphs"); + appcstrg(&lcppflgs, "-pedantic"); + appcstrg(&lcppflgs, "-D__STRICT_ANSI__"); + appcstrg(&l1flags, "-s"); + appcstrg(&l2flags, "-s"); + sflag = 1; + break; + + case 't': + if (sflag) + usage(); + freelst(&lcppflgs); + appcstrg(&lcppflgs, "-traditional"); + appstrg(&lcppflgs, concat2("-D", MACHINE)); + appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH)); + appcstrg(&l1flags, "-t"); + appcstrg(&l2flags, "-t"); + tflag = 1; + break; + + case 'x': + appcstrg(&l2flags, "-x"); + break; + + case 'C': + if (Cflag || oflag || iflag) + usage(); + Cflag = 1; + appstrg(&l2flags, concat2("-C", optarg)); + p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg)); + (void)sprintf(p2out, "llib-l%s.ln", optarg); + freelst(&deflibs); + break; + + case 'D': + case 'I': + case 'U': + (void)sprintf(flgbuf, "-%c", c); + appstrg(&cppflags, concat2(flgbuf, optarg)); + break; + + case 'l': + appcstrg(&libs, optarg); + break; + + case 'o': + if (Cflag || oflag) + usage(); + oflag = 1; + outputfn = xstrdup(optarg); + break; + + case 'L': + appcstrg(&libsrchpath, optarg); + break; + + case 'H': + appcstrg(&l2flags, "-H"); + break; + + case 'V': + Vflag = 1; + break; + + case '?': + usage(); + /* NOTREACHED */ + + case -1: + /* filename */ + fname(argv[0], argc == 1); + first = 0; + optind = 1; + } + + } + + if (first) + usage(); + + if (iflag) + terminate(0); + + if (!oflag) { + if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0) + s = PATH_LINTLIB; + appcstrg(&libsrchpath, s); + findlibs(libs); + findlibs(deflibs); + } + + (void)printf("Lint pass2:\n"); + lint2(); + + if (oflag) + cat(p2in, outputfn); + + if (Cflag) + p2out = NULL; + + terminate(0); + /* NOTREACHED */ +} + +/* + * Read a file name from the command line + * and pass it through lint1 if it is a C source. + */ +static void +fname(name, last) + const char *name; + int last; +{ + const char *bn, *suff; + char **args, *ofn, *path; + size_t len; + + bn = basename(name, '/'); + suff = basename(bn, '.'); + + if (strcmp(suff, "ln") == 0) { + /* only for lint2 */ + if (!iflag) + appcstrg(&p2in, name); + return; + } + + if (strcmp(suff, "c") != 0 && + (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) { + warnx("unknown file type: %s\n", name); + return; + } + + if (!iflag || !first || !last) + (void)printf("%s:\n", Fflag ? name : bn); + + /* build the name of the output file of lint1 */ + if (oflag) { + ofn = outputfn; + outputfn = NULL; + oflag = 0; + } else if (iflag) { + ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2)); + len = bn == suff ? strlen(bn) : (suff - 1) - bn; + (void)sprintf(ofn, "%.*s", (int)len, bn); + (void)strcat(ofn, ".ln"); + } else { + ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX")); + (void)sprintf(ofn, "%slint1.XXXXXX", tmpdir); + if (mktemp(ofn) == NULL) { + warn("can't make temp"); + terminate(-1); + } + } + if (!iflag) + appcstrg(&p1out, ofn); + + args = xcalloc(1, sizeof (char *)); + + /* run cpp */ + + path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/cpp")); + (void)sprintf(path, "%s/cpp", PATH_LIBEXEC); + + appcstrg(&args, path); + applst(&args, cppflags); + applst(&args, lcppflgs); + appcstrg(&args, name); + appcstrg(&args, cppout); + + runchild(path, args, cppout); + free(path); + freelst(&args); + + /* run lint1 */ + + path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1")); + (void)sprintf(path, "%s/lint1", PATH_LIBEXEC); + + appcstrg(&args, path); + applst(&args, l1flags); + appcstrg(&args, cppout); + appcstrg(&args, ofn); + + runchild(path, args, ofn); + free(path); + freelst(&args); + + appcstrg(&p2in, ofn); + free(ofn); + + free(args); +} + +static void +runchild(path, args, crfn) + const char *path, *crfn; + char *const *args; +{ + int status, rv, signo, i; + + if (Vflag) { + for (i = 0; args[i] != NULL; i++) + (void)printf("%s ", args[i]); + (void)printf("\n"); + } + + currfn = crfn; + + (void)fflush(stdout); + + switch (fork()) { + case -1: + warn("cannot fork"); + terminate(-1); + /* NOTREACHED */ + default: + /* parent */ + break; + case 0: + /* child */ + (void)execv(path, args); + warn("cannot exec %s", path); + exit(1); + /* NOTREACHED */ + } + + while ((rv = wait(&status)) == -1 && errno == EINTR) ; + if (rv == -1) { + warn("wait"); + terminate(-1); + } + if (WIFSIGNALED(status)) { + signo = WTERMSIG(status); + warnx("%s got SIG%s", path, sys_signame[signo]); + terminate(-1); + } + if (WEXITSTATUS(status) != 0) + terminate(-1); + currfn = NULL; +} + +static void +findlibs(liblst) + char *const *liblst; +{ + int i, k; + const char *lib, *path; + char *lfn; + size_t len; + + lfn = NULL; + + for (i = 0; (lib = liblst[i]) != NULL; i++) { + for (k = 0; (path = libsrchpath[k]) != NULL; k++) { + len = strlen(path) + strlen(lib); + lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln")); + (void)sprintf(lfn, "%s/llib-l%s.ln", path, lib); + if (rdok(lfn)) + break; + lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln")); + (void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib); + if (rdok(lfn)) + break; + } + if (path != NULL) { + appstrg(&l2libs, concat2("-l", lfn)); + } else { + warnx("cannot find llib-l%s.ln", lib); + } + } + + free(lfn); +} + +static int +rdok(path) + const char *path; +{ + struct stat sbuf; + + if (stat(path, &sbuf) == -1) + return (0); + if ((sbuf.st_mode & S_IFMT) != S_IFREG) + return (0); + if (access(path, R_OK) == -1) + return (0); + return (1); +} + +static void +lint2() +{ + char *path, **args; + + args = xcalloc(1, sizeof (char *)); + + path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2")); + (void)sprintf(path, "%s/lint2", PATH_LIBEXEC); + + appcstrg(&args, path); + applst(&args, l2flags); + applst(&args, l2libs); + applst(&args, p2in); + + runchild(path, args, p2out); + free(path); + freelst(&args); + free(args); +} + +static void +cat(srcs, dest) + char *const *srcs; + const char *dest; +{ + int ifd, ofd, i; + char *src, *buf; + ssize_t rlen; + + if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) { + warn("cannot open %s", dest); + terminate(-1); + } + + buf = xmalloc(MBLKSIZ); + + for (i = 0; (src = srcs[i]) != NULL; i++) { + if ((ifd = open(src, O_RDONLY)) == -1) { + free(buf); + warn("cannot open %s", src); + terminate(-1); + } + do { + if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) { + free(buf); + warn("read error on %s", src); + terminate(-1); + } + if (write(ofd, buf, (size_t)rlen) == -1) { + free(buf); + warn("write error on %s", dest); + terminate(-1); + } + } while (rlen == MBLKSIZ); + (void)close(ifd); + } + (void)close(ofd); + free(buf); +} + |