#! /sbin/sh
#	Copyright (c) 1989 AT&T
#	  All Rights Reserved

#	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T
#	The copyright notice above does not evidence any
#	actual or intended publication of such source code.
#
# Copyright 09/19/95 Sun Microsystems, Inc. All Rights Reserved
#
#ident "xxxxx"
# "@(#)RELEASE VERSION PC3.0.1 patch 102486-02 03 Aug 1995"
#



TEMP=`echo $0 | awk '{print substr($0,1,1)}'`
if [ $TEMP = "/" -o $TEMP = "." ]
then
	whatdir_dir=`dirname $0`
	WHATDIR=`$whatdir_dir/whatdir $0`
else
	WHATDIR=`whatdir $0`
fi


TMPDIR=${TMPDIR:-/tmp}		# where to put temporary files
LPASS=${CCSLIB:-$WHATDIR}	# where pass 1 and pass2 are found
LLDIR=${CCSLIB:-/usr/ccs/lib}	# where lint libraries are found
TOUT=$TMPDIR/tlint.$$		# combined input for second pass
T1=$TMPDIR/tlint1$$		# definitions from C source
T2=$TMPDIR/tlint2$$		# tentative definitions from C source
T3=$TMPDIR/tlint3$$		# function calls, misc
T4=$TMPDIR/tlint4$$		# strings for printf/scanf checking
TCPP=$TMPDIR/tlint.cpp.$$.i 	# temporary file for cpp output in -Xs mode
HOUT=$TMPDIR/hlint$$		# header messages file
NOUT=$TMPDIR/nlint$$		# holds names of included files
LINT1=$LPASS/lint1		# pass 1 of lint
LINT2=$LPASS/lint2		# pass 2 of lint
CPP=cpp				# preprocessor for -Xs mode
PATH=/bin:/usr/bin:/usr/ccs/lib

ARCH=i386
CPPF="-C"	# options for cpp part of lint1
LINTF=				# options for the lint passes
FILES=				# the *.c and *.ln files in order
NDOTC=0				# how many *.c were there
DEFL=/usr/lib/llib-lc.ln	# the default lint library to use
LLIB=				# lint library file to create
LNOUT=				# for cflow
CXOUT=				# for cxref
CONLY=				# set for compile only (no second pass)
CFILEONLY=			# name of output file when -C specified
PREONLY=			# run cpp only on file
FULLPATH=			# set if -F option
FUNCDEF=			# suppress old style def/decl warnings
DIRLST=				# ordered list of args to -L option
LIBLST=				# lint libs to look for in DIRLST
RETVAL=
EXIT=0				# Normal exit code
VERSION=
ERRORS=				# list of files with errors in them
AMODE=t				# ANSI modes: -Xt, -Xa, -Xc -Xs
VERBOSE=0
DASHDASH=                       # "--" found in command line

TMPFILES="$TOUT $HOUT $NOUT $T1 $T2 $T3 $T4 $TCPP"

trap "rm -f $TMPFILES; exit 2" 1 2 3 15

USAGE="Usage: lint [-abcfdhkmnpsuvxyFV] [-lx] [-o lib] [-L libdir] file ..."
BADUSE="lint: file with unknown suffix ignored:"
OPTARG=abcC:f:ghkl:mno:spuvxyD:FVI:L:U:O1:2:X:PW:R:Y:E#
set -- `getopt $OPTARG "$@"`
if [ $? -ne 0 ]
then
    echo $USAGE >&2
    exit 2
fi
while [ $# -gt 0 ]
do
    case $1 in
	-#)	shift; 
		VERBOSE=`expr $VERBOSE + 1`;;
	-p)	LINTF="$LINTF $1"; shift;;
	-f)     if [ $2 != "d" ]
		then
		    echo "lint: bad option: -f$2" >&2
		    exit 2
		else
	  	    FUNCDEF="$1$2"
		fi;
		shift 2;;
	-n)	shift; DEFL=;;
	-c)	shift; CONLY=1;;
#
# W option for cfloW only - makes output go to specified file
# R option for cxRef only - makes identifier output go to specified file
#
	-C)	CFILEONLY="$2"; shift 2;;
	-W)	LINTF="$LINTF $1"; LNOUT="$2"; shift 2;;
	-R)	LINTF="$LINTF $1$2"; CXOUT="$2"; shift 2;;
	-[abhkmsuvxy]) LINTF="$LINTF $1"; shift;;
	-V)	LINTF="$LINTF $1"; VERSION=1; shift;;
	-F)	LINTF="$LINTF $1"; FULLPATH=1; shift;;
	-[IDU]) CPPF="$CPPF $1$2"; shift 2;;
	-[PE])	CPPF="$CPPF $1"; shift; PREONLY=1;;
	-L)	DIRLST="$DIRLST $2"; shift 2;;
	-l)	LIBLST="$LIBLST llib-l$2.ln";
		shift 2;;
	-o)	OPT=`basename $2`; LLIB="llib-l$2.ln"; shift 2;;
	-[12])	LINTF="$LINTF $1$2"; shift 2;;
	-X)	LINTF="$LINTF $1$2"; AMODE=$2; shift 2;;
        -Y)     SUBOPT=`echo $2 | cut -c 1-2`
                SUBOPTARG=`echo $2 | cut -c 3-`
                if [ "$SUBOPT" = "E," ]
                then
                        LINT1=$SUBOPTARG/`basename $LINT1`
                        LINT2=$SUBOPTARG/`basename $LINT2`
                elif [ "$SUBOPT" = "L," ]
                then
                        LLDIR=$SUBOPTARG
			if [ "$DEFL" != "" ]
			then
                        	DEFL=$LLDIR/llib-lc.ln
			fi
                elif [ "$SUBOPT" = "I," ]
                then
                        CPPF="$CPPF $1$SUBOPTARG"
                else
                        CPPF="$CPPF $1$2"
                fi
                shift 2;;
#
# some cc options to be ignored.
#
	-[Og])	shift;;
	--)	shift;
		DASHDASH="--";
		while [ $# -gt 0 ]
		do
		    case $1 in	
			#
                        # Deleted -*) case here for processing options.
                        # XPG4 standard requires any arg after '--'
                        # to be processed as operand.
                        #
			*.[cis])	FILES="$FILES $1"
				NDOTC=`expr $NDOTC + 1`
				shift;;
			*.ln)	FILES="$FILES $1"; shift;;
#
# If making a lint library, then allow any suffix.  This is because
# lint libraries typically look like: llib-lX where X stands for the
# library (i.e. llib-lc, llib-lm, llib-lmalloc, etc ...)
# 
			*)	if [ ! "$LLIB" ]
				then
				    echo $BADUSE $1 >&2
				else
				    FILES="$FILES $1"
				    NDOTC=`expr $NDOTC + 1`
				fi
				shift;;
		    esac
		done
		;;
	-*)	echo "lint: bad option ignored: $1" >&2;;
    esac
done

CPPF="$CPPF -I${WHATDIR}/../include/cc"

# don't append assertion in -Xs mode
if [ "$AMODE" != "s" ]
then
        CPPF="$CPPF -Alint(on)"
fi

#
# Only use -Dlint if this isn't running as cxref (CXOUT) or
# as cflow (LNOUT) or mode is not -Xc
#
if [ "$LNOUT" = "" -a "$CXOUT" = "" ]
then
	if [ "$AMODE" != "c" ]
	then
		CPPF="$CPPF -Dlint -D__lint"
	else
		CPPF="$CPPF -D__lint"
	fi
fi

# append  predefines for all modes
CPPF="$CPPF -D__SUNPRO_C=0x301 -D__SVR4 -D__sun -D__unix -D__$ARCH"

# don't append -Dsun -Dunix or -Dsparc in -Xc mode
if [ "$AMODE" != "c" ]
then
	CPPF="$CPPF -Dsun -Dunix -D$ARCH" 
fi
	

# Give something to lint to do!
if [ "$FILES" = "" ]
then
	if [ "$VERSION" = "" ]
	then
		echo "lint: no file arguments" >&2
		exit 1
	else
		$LINT1 -V
		exit 0
	fi
fi

#
# Check to see if all the lint libraries specified on the command line
# can be found either in the initial lint directory (normally /usr/ccs/lib),
# in /usr/lib, or in one of the user specified directories (via -L <dir>).
#
LLDIR="$DIRLST $WHATDIR/../lib $LLDIR /usr/lib"
for LIB in $LIBLST
do
    for DIR in $LLDIR
    do
        if [ -r "$DIR"/"$LIB" ]
        then
            FILES="$FILES $DIR/$LIB"
            break
        fi
    done
    if [ ! -r "$DIR"/"$LIB" ]
    then
        echo "lint: $LIB not found" >&2
    fi
done

#
# Run pass1 only, creating .ln files.
# Any .ln files on the command line will be ignored.
#
if [ "$CONLY" -o "$PREONLY" -o "$CFILEONLY" ]
then
    for i in $FILES
    do
	case $i in
	*.ln)	;;
	*)	if [ "$CFILEONLY" ]
		then
			T=$CFILEONLY.ln
		else
			T=`basename $i .c`
			if [ $T = `basename $i` ] 
			then	
				T=`basename $i .i`
				if [ $T = `basename $i` ] 
				then
					T=`basename $i .s`
				fi
			fi
			T=$T.ln
		fi
		if [ "$FULLPATH" ]
		then
		    FNAME=$i
		else
		    FNAME=`basename $i`
		fi

		if [ $NDOTC -gt 1 ]
		then
		    echo $FNAME:
		fi
                if [ $AMODE = "s" -a `basename $FNAME.c`  != $FNAME ]
                then
			if [ $VERBOSE != 0 ]
			then
                        	echo "$CPP -P $CPPF $DASHDASH $i $TCPP"
			fi
			if [ $VERBOSE -lt 3 ]
			then
                        	$CPP -P $CPPF $DASHDASH $i $TCPP
                        	RETVAL=$?
			else
				RETVAL=0
			fi
                        if [ $RETVAL = 0 ]
                        then
				if [ $VERBOSE != 0 ]
				then
					echo "$LINT1 $CPPF $FUNCDEF $LINTF -T $HOUT,$NOUT,$T1,$T2,$T3,$T4 $TCPP"
				fi
				if [ $VERBOSE -lt 3 ]
				then
                                	$LINT1 $CPPF $FUNCDEF $LINTF -T $HOUT,$NOUT,$T1,$T2,$T3,$T4 $TCPP
                                	RETVAL=$?
				else
					RETVAL=0
				fi
                        else
                                echo "lint: errors in cpp for $FNAME; no output created" >&2
                                EXIT=$RETVAL
                        fi
                else
			if [ $VERBOSE != 0 ]
			then
				echo "$LINT1 $CPPF $FUNCDEF $LINTF -T $HOUT,$NOUT,$T1,$T2,$T3,$T4 $DASHDASH $i"
			fi
			if [ $VERBOSE -lt 3 ]
			then
                        	$LINT1 $CPPF $FUNCDEF $LINTF -T $HOUT,$NOUT,$T1,$T2,$T3,$T4 $DASHDASH $i
                        	RETVAL=$?
			else
				RETVAL=0
			fi
                fi

#
# If return value is 0, save the output to the .ln file, and print
# header file warnings.
# 
		if [ $RETVAL = 0 ]
		then
		    if [ ! "$PREONLY" ]
		    then
			if [ $VERBOSE -lt 3 ]
			then
				cat $T1 $T2 $T3 $T4 > $T
			fi
			if [ -f $HOUT ]
			then
				cat -s $HOUT
			fi
		    fi
		else
		    if [ -f $HOUT ]
		    then
		    	cat -s $HOUT
		    fi
		    echo "lint: errors in $FNAME; no output created" >&2
		    EXIT=$RETVAL
		fi
		rm -f $HOUT $NOUT;;
	esac
    done
else
    for i in $FILES
    do
	case $i in
	*.ln)	cat <$i >> $TOUT;;
	*)	if [ "$FULLPATH" ]
		then
		    FNAME=$i
		else
		    FNAME=`basename $i`
		fi

		if [ $NDOTC -gt 1 ]
		then
		    echo $FNAME:
		fi
                if [ $AMODE = "s" -a `basename $i .c`  != $FNAME ]
                then
			if [ $VERBOSE != 0 ]
			then
                        	echo "$CPP -P $CPPF $DASHDASH $i $TCPP"
			fi
			if [ $VERBOSE -lt 3 ]
			then
                        	$CPP -P $CPPF $DASHDASH $i $TCPP
                        	RETVAL=$?
			else
				RETVAL=0
			fi
                        if [ $RETVAL = 0 ]
                        then
				if [ $VERBOSE != 0 ]
				then
					echo "$LINT1 $CPPF $FUNCDEF $LINTF -T $HOUT,$NOUT,$T1,$T2,$T3,$T4 $TCPP"
				fi
				if [ $VERBOSE -lt 3 ]
				then
                                	$LINT1 $CPPF $FUNCDEF $LINTF -T $HOUT,$NOUT,$T1,$T2,$T3,$T4 $TCPP
                                	RETVAL=$?
				else
                                	RETVAL=0
				fi
                        else
                                echo "lint: errors in cpp for $FNAME; no output created" >&2
                                EXIT=$RETVAL
                        fi
                else
			if [ $VERBOSE != 0 ]
			then
				echo "$LINT1 $CPPF $FUNCDEF $LINTF -T $HOUT,$NOUT,$T1,$T2,$T3,$T4 $DASHDASH $i"
			fi
			if [ $VERBOSE -lt 3 ]
			then
                        	$LINT1 $CPPF $FUNCDEF $LINTF -T $HOUT,$NOUT,$T1,$T2,$T3,$T4 $DASHDASH $i
				RETVAL=$?
			else
				RETVAL=0
			fi
                fi

#
# If return value ok, save into temp file for later use by lint2.
# Otherwise, cat the header file messages, and indicate there was
# a problem.
#
		if [ $RETVAL = 0 ]
		then
			if [ $VERBOSE -lt 3 ]
			then
		    		cat $T1 $T2 $T3 $T4 >> $TOUT
			fi
		else
			#rm -f $HOUT $NOUT
		    	echo "lint: errors in $FNAME; no output created" >&2
		    	if [ "$ERRORS" = "" ]
		    	then
				ERRORS=$FNAME
		    	else
				ERRORS="$ERRORS,$FNAME"
		    	fi
		    	EXIT=$RETVAL
		fi
		;;
	esac
    done

    if [ $EXIT != 0 ]
    then
	if [ -f $HOUT ]
	then
		cat -s $HOUT
	fi
	rm -f $TMPFILES
	echo "lint: pass2 not run - errors in $ERRORS" >&2
	exit $EXIT
    fi

# A lint library is to be created.
    if [ "$LLIB" ]
    then
	cp $TOUT $LLIB
    fi

    if [ "$LNOUT" ]
    then
	cp $TOUT $LNOUT
	rm -f $TMPFILES
	exit 0
    fi

    if [ "$CXOUT" ]
    then
	rm -f $TMPFILES
	exit 0
    fi

# Add in the default lint library (if -n was not used)
    if [ "$DEFL" ]
    then
	cat <$DEFL >> $TOUT
    fi

# Print the errors/warnings from the header file
    if [ -f $HOUT ]
    then
    	cat -s $HOUT
    fi

    if [ $VERBOSE != 0 ]
    then
    	echo "$LINT2 $LINTF $TOUT"
    fi
    if [ $VERBOSE -lt 3 ]
    then
   	 $LINT2 $LINTF $TOUT
    	RETVAL=$?
    else
	RETVAL=0
    fi
    if [ $RETVAL != 0 ]
    then
	rm -f $TMPFILES
	exit $RETVAL
    fi
fi

rm -f $TMPFILES
exit $EXIT
