static char sccsid
[] = "@(#)lint.c 1.14 (Berkeley) %G%";
/* these are appropriate for the -p flag */
int nflag
= 0; /* avoid gripes about printf et al. */
int vflag
= 1; /* tell about unused argments */
int xflag
= 0; /* tell about unused externals */
int argflag
= 0; /* used to turn off complaints about arguments */
int libflag
= 0; /* used to generate library descriptions */
int vaflag
= -1; /* signal functions with a variable number of args */
int aflag
= 0; /* used to check precision of assignments */
int zflag
= 0; /* no 'structure never defined' error */
int Cflag
= 0; /* filter out certain output, for generating libraries */
char *libname
= 0; /* name of the library we're generating */
/* flags for the "outdef" function */
contx( p
, down
, pl
, pr
) register NODE
*p
; register *pl
, *pr
; {
if( asgop(p
->in
.op
) ) break;
if( p
->in
.op
== UNARY MUL
&& ( p
->in
.type
== STRTY
|| p
->in
.type
== UNIONTY
|| p
->in
.type
== UNDEF
) ) {
/* struct x f( ); main( ) { (void) f( ); }
* the the cast call appears as U* UNDEF
break; /* the compiler does this... */
if( down
== EFF
&& hflag
) werror( "null effect" );
/* called after processing each job */
/* flag is nonzero if errors were detected */
register struct symtab
*p
;
for( p
=stab
; p
< &stab
[SYMTSZ
]; ++p
){
if( p
->stype
!= TNULL
) {
if( p
->stype
== STRTY
|| p
->stype
== UNIONTY
){
if( !zflag
&& dimtab
[p
->sizoff
+1] < 0 ){
if( hflag
) werror( "struct/union %.8s never defined", p
->sname
);
if( hflag
) werror( "struct/union %s never defined", p
->sname
);
uerror( "static variable %.8s unused",
uerror( "static variable %s unused",
/* no statics in libraries */
/* with the xflag, worry about externs not used */
/* the filename may be wrong here... */
if( xflag
&& p
->suse
>= 0 && !libflag
){
outdef( p
, LDX
, NOFILE
);
if( p
->suse
< 0 ){ /* used */
outdef( p
, LUM
, SVLINE
);
astype( t
, i
) ATYPE
*t
; {
if( (tt
=BTYPE(t
->aty
))==STRTY
|| tt
==UNIONTY
){
if( i
<0 || i
>= DIMTABSZ
-3 ){
werror( "lint's little mind is blown" );
l
= X_NONAME
| stab
[j
].suse
;
if( stab
[j
].suse
<= 0 ) {
werror( "no line number for %.8s",
werror( "no line number for %s",
l
= hashstr(stab
[j
].sname
);
l
= hashstr(stab
[j
].sname
, LCHNM
);
bfcode( a
, n
) int a
[]; {
/* code for the beginning of a function; a is an array of
indices in stab for the arguments; n is the number */
/* this must also set retlab */
register struct symtab
*cfp
;
/* if creating library, don't do static functions */
if( Cflag
&& cfp
->sclass
== STATIC
) return;
/* if variable number of arguments, only print the ones which will be checked */
if( n
< vaflag
) werror( "declare the VARARGS arguments you want checked!" );
if( cfp
->sclass
== STATIC
) outdef( cfp
, LST
, vaflag
>=0?~n
:n
);
else outdef( cfp
, libflag
?LIB
:LDI
, vaflag
>=0?~n
:n
);
/* output the arguments */
t
.aty
= stab
[a
[i
]].stype
;
if( !astype( &t
, stab
[a
[i
]].sizoff
) ) {
fwrite( (char *)&t
, sizeof(ATYPE
), 1, stdout
);
/* count arguments; p points to at least one */
/* the arguemnts are a tower of commas to the left */
c
= 1; /* count the rhs */
t
.extra
= (p
->in
.op
==ICON
);
if( !astype( &t
, p
->fn
.csiz
) ) {
fwrite( (char *)&t
, sizeof(ATYPE
), 1, stdout
);
lprt( p
, down
, uses
) register NODE
*p
; {
register struct symtab
*q
;
register struct lnm
*np1
, *np2
;
/* first, set variables which are set... */
if( p
->in
.op
== ASSIGN
) use1
= VALSET
;
else if( p
->in
.op
== UNARY AND
) use1
= VALADDR
;
else if( asgop( p
->in
.op
) ){ /* =ops */
if( down
== EFF
) use1
|= VALASGOP
;
/* print the lines for lint */
if( p
->in
.left
->in
.type
== CHAR
&& p
->in
.right
->in
.op
==ICON
&& p
->in
.right
->tn
.lval
< 0 ){
werror( "nonportable character comparison" );
if( (p
->in
.op
==EQ
|| p
->in
.op
==NE
) && ISUNSIGNED(p
->in
.left
->in
.type
) && p
->in
.right
->in
.op
== ICON
){
if( p
->in
.right
->tn
.lval
< 0 && p
->in
.right
->tn
.rval
== NONAME
&& !ISUNSIGNED(p
->in
.right
->in
.type
) ){
werror( "comparison of unsigned with negative constant" );
if( p
->in
.right
->in
.op
== ICON
&& p
->in
.right
->tn
.lval
== 0 && p
->in
.right
->tn
.rval
== NONAME
){
werror( "unsigned comparison with 0?" );
if( p
->in
.right
->in
.op
== ICON
&& p
->in
.right
->tn
.lval
<= 0 && !ISUNSIGNED(p
->in
.right
->in
.type
) && p
->in
.right
->tn
.rval
== NONAME
){
werror( "degenerate unsigned comparison" );
/* go recursively left, then right */
lprt( p
->in
.left
, down1
, use1
);
lprt( p
->in
.right
, down2
, use2
);
acount
= ctargs( p
->in
.right
);
if( p
->in
.left
->in
.op
== ICON
&& (id
=p
->in
.left
->tn
.rval
) != NONAME
){ /* used to be &name */
struct symtab
*sp
= &stab
[id
];
* if we're generating a library -C then
* we don't want to output references to functions
/* if a function used in an effects context is
* cast to type void then consider its value
* to have been disposed of properly
* thus a call of type undef in an effects
* context is construed to be used in a value
if ((down
== EFF
) && (p
->in
.type
!= UNDEF
)) {
} else if (down
== EFF
) {
outdef( sp
, lty
, acount
);
/* look for &name case */
if( (id
= p
->tn
.rval
) >= 0 && id
!= NONAME
){
q
->sflags
|= (SREF
|SSET
);
if( (id
= p
->tn
.rval
) >= 0 && id
!= NONAME
){
if( (uses
&VALUSED
) && !(q
->sflags
&SSET
) ){
if( q
->sclass
== AUTO
|| q
->sclass
== REGISTER
){
if( !ISARY(q
->stype
) && !ISFTN(q
->stype
) && q
->stype
!=STRTY
&& q
->stype
!=UNIONTY
){
werror( "%.8s may be used before set", q
->sname
);
werror( "%s may be used before set", q
->sname
);
if( uses
& VALASGOP
) break; /* not a real use */
if( uses
& VALSET
) q
->sflags
|= SSET
;
if( uses
& VALUSED
) q
->sflags
|= SREF
;
if( uses
& VALADDR
) q
->sflags
|= (SREF
|SSET
);
lnp
->flgs
= (uses
&VALADDR
)?0:((uses
&VALSET
)?VALSET
:VALUSED
);
if( ++lnp
>= &lnames
[LNAMES
] ) --lnp
;
/* recurse, going down the right side first if we can */
switch( optype(p
->in
.op
) ){
lprt( p
->in
.right
, down2
, use2
);
lprt( p
->in
.left
, down1
, use1
);
if( optype(p
->in
.op
) == BITYPE
){
if( p
->in
.op
== ASSIGN
&& p
->in
.left
->in
.op
== NAME
){ /* special case for a = .. a .. */
else lmerge( np1
, np2
, p
->in
.op
!= COLON
);
/* look for assignments to fields, and complain */
if( p
->in
.op
== ASSIGN
&& p
->in
.left
->in
.op
== FLD
&& p
->in
.right
->in
.op
== ICON
) fldcon( p
);
lmerge( np1
, np2
, flag
) struct lnm
*np1
, *np2
; {
/* np1 and np2 point to lists of lnm members, for the two sides
* flag is 1 if commutation is possible, 0 otherwise
* lmerge returns a merged list, starting at np1, resetting lnp
* it also complains, if appropriate, about side effects
register struct lnm
*npx
, *npy
;
for( npx
= np2
; npx
< lnp
; ++npx
){
/* is it already there? */
for( npy
= np1
; npy
< np2
; ++npy
){
if( npx
->lid
== npy
->lid
){ /* yes */
if( npx
->flgs
== 0 || npx
->flgs
== (VALSET
|VALUSED
) )
else if( (npx
->flgs
|npy
->flgs
)== (VALSET
|VALUSED
) ||
(npx
->flgs
&npy
->flgs
&VALSET
) ){
if( flag
) werror( "%.8s evaluation order undefined", stab
[npy
->lid
].sname
);
if( flag
) werror( "%s evaluation order undefined", stab
[npy
->lid
].sname
);
if( npy
->flgs
== 0 ) npx
->flgs
= 0;
else npy
->flgs
|= npx
->flgs
;
/* not there: update entry */
/* all finished: merged list is at np1 */
/* code for the end of a function */
register struct symtab
*cfp
;
if( retstat
& RETVAL
&& !(Cflag
&& cfp
->sclass
==STATIC
) )
outdef( cfp
, LRV
, DECTY
);
if( retstat
== RETVAL
+NRETVAL
)
werror( "function %.8s has return(e); and return;", cfp
->sname
);
werror( "function %s has return(e); and return;", cfp
->sname
);
aocode(p
) struct symtab
*p
; {
/* called when automatic p removed from stab */
register struct symtab
*cfs
;
if(p
->suse
>0 && !(p
->sflags
&(SMOS
|STAG
)) ){
if( p
->sclass
== PARAM
){
if( vflag
) werror( "argument %.8s unused in function %.8s",
if( vflag
) werror( "argument %s unused in function %s",
if( p
->sclass
!= TYPEDEF
) werror( "%.8s unused in function %.8s",
if( p
->sclass
!= TYPEDEF
) werror( "%s unused in function %s",
if( p
->suse
< 0 && (p
->sflags
& (SSET
|SREF
|SMOS
)) == SSET
&&
!ISARY(p
->stype
) && !ISFTN(p
->stype
) ){
werror( "%.8s set but not used in function %.8s", p
->sname
, cfs
->sname
);
werror( "%s set but not used in function %s", p
->sname
, cfs
->sname
);
if( p
->stype
== STRTY
|| p
->stype
== UNIONTY
|| p
->stype
== ENUMTY
){
if( !zflag
&& dimtab
[p
->sizoff
+1] < 0 )
werror( "structure %.8s never defined", p
->sname
);
werror( "structure %s never defined", p
->sname
);
defnam( p
) register struct symtab
*p
; {
/* define the current location as the name p->sname */
if( p
->sclass
== STATIC
&& (p
->slevel
>1 || Cflag
) ) return;
if( p
->sclass
== STATIC
) outdef( p
, LST
, USUAL
);
else outdef( p
, libflag
?LIB
:LDI
, USUAL
);
/* n integer words of zeros */
andable( p
) NODE
*p
; { /* p is a NAME node; can it accept & ? */
if( p
->in
.op
!= NAME
) cerror( "andable error" );
if( (r
= p
->tn
.rval
) < 0 ) return(1); /* labels are andable */
if( stab
[r
].sclass
== AUTO
|| stab
[r
].sclass
== PARAM
) return(0);
if( stab
[r
].sclass
== REGISTER
) uerror( "can't take & of %.8s", stab
[r
].sname
);
if( stab
[r
].sclass
== REGISTER
) uerror( "can't take & of %s", stab
[r
].sname
);
/* this is called to do local transformations on
an expression tree preparitory to its being
written out in intermediate code.
/* the major essential job is rewriting the
automatic variables and arguments in terms of
/* conversion ops which are not necessary are also clobbered here */
/* in addition, any special features (such as rewriting
exclusive or) are easily handled here as well */
extern int didstr
, subscr
;
extern NODE
* strnodes
[];
if( p
->in
.left
->in
.type
==ENUMTY
){
p
->in
.left
= pconvert( p
->in
.left
);
/* assume conversion takes place; type is inherited */
tl
= p
->in
.left
->in
.type
;
if( aflag
&& (tl
==LONG
||tl
==ULONG
) && (t
!=LONG
&&t
!=ULONG
&&t
!=UNDEF
) ){
werror( "long assignment may lose accuracy" );
if( aflag
>=2 && (tl
!=LONG
&&tl
!=ULONG
) && (t
==LONG
||t
==ULONG
) && p
->in
.left
->in
.op
!= ICON
){
werror( "assignment to long may sign-extend incorrectly" );
if( ISPTR(tl
) && ISPTR(t
) ){
switch( ISFTN(t
) + ISFTN(tl
) ){
case 0: /* neither is a function pointer */
if( talign(t
,p
->fn
.csiz
) > talign(tl
,p
->in
.left
->fn
.csiz
) ){
if( hflag
||pflag
) werror( "possible pointer alignment problem" );
werror( "questionable conversion of function pointer" );
p
->in
.left
->in
.type
= p
->in
.type
;
p
->in
.left
->fn
.cdim
= p
->fn
.cdim
;
p
->in
.left
->fn
.csiz
= p
->fn
.csiz
;
if( p
->in
.right
->in
.op
!= ICON
) cerror( "bad conversion");
return( buildtree( o
==PMCONV
?MUL
:DIV
, p
->in
.left
, p
->in
.right
) );
if( p
->in
.right
->in
.op
!= ICON
)
s
= p
->in
.right
->tn
.lval
;
werror( "negative shift" );
if( s
>= dimtab
[ p
->fn
.csiz
] )
werror( "shift greater than size of object" );
offcon( off
, t
, d
, s
) OFFSZ off
; TWORD t
;{ /* make a structure offset node */
/* storage class for such as "int a;" */
return( pflag
? EXTDEF
: EXTERN
);
cinit( p
, sz
) NODE
*p
; { /* initialize p into size sz */
if( p
->in
.left
->in
.op
== ICON
) return;
if( p
->in
.left
->in
.op
== NAME
&& p
->in
.left
->in
.type
== MOE
) return;
uerror( "illegal initialization" );
/* make a name look like an external name in the local machine */
if( isupper(*p
) ) aa
[i
] = tolower( *p
);
static int stripping
= 0;
/* PATCHED by ROBERT HENRY on 8Jul80 to fix 14 character file name bug */
cerror( "filename too long" );
if( strncmp( s
, fsname
.f
.fn
, LFNM
) )
if (fsname
.f
.fn
== NULL
|| strcmp(s
, fsname
.f
.fn
))
strncpy( fsname
.f
.fn
, s
, LFNM
);
fwrite( (char *)&fsname
, sizeof(fsname
), 1, stdout
);
/* if generating a library, prefix with the library name */
/* only do this for flexnames */
fwrite( libname
, strlen(libname
), 1, stdout
);
fwrite( fsname
.f
.fn
, strlen(fsname
.f
.fn
)+1, 1, stdout
);
where(f
){ /* print true location of error */
if( f
== 'u' && nerrors
> 1 )
--nerrors
; /* don't get "too many errors" */
fprintf( stderr
, "%s(%d): ", strip(ftitle
), lineno
);
/* a number of dummy routines, unneeded by lint */
static char * strings
[SBUFSIZE
];
static NODE
* strnodes
[SBUFSIZE
];
if (subscr
< (SBUFSIZE
- 1))
strings
[subscr
] = (strings
[subscr
] == NULL
) ?
calloc((size_t) (SCLICK
+ 1), 1) :
realloc(strings
[subscr
], (size_t) (i
+ SCLICK
+ 1));
if (strings
[subscr
] == NULL
) {
case CHAR
: return "char";
case UCHAR
: return "unsigned char";
case SHORT
: return "short";
case USHORT
: return "unsigned short";
case UNSIGNED
: return "unsigned";
case ENUMTY
: return "enum";
case LONG
: return "long";
case ULONG
: return "unsigned long";
case FLOAT
: return "float";
case DOUBLE
: return "double";
case STRTY
: return "struct";
case UNIONTY
: return "union";
case PTR
|CHAR
: return "char *";
case PTR
|UCHAR
: return "unsigned char *";
case PTR
|SHORT
: return "short *";
case PTR
|USHORT
: return "unsigned short *";
case PTR
|INT
: return "int *";
case PTR
|UNSIGNED
: return "unsigned *";
case PTR
|ENUMTY
: return "enum *";
case PTR
|LONG
: return "long *";
case PTR
|ULONG
: return "unsigned long *";
case PTR
|FLOAT
: return "float *";
case PTR
|DOUBLE
: return "double *";
case PTR
|STRTY
: return "struct *";
case PTR
|UNIONTY
: return "union *";
default: return ISPTR(t
) ?
"pointer" : "non-scalar";
return (n
== 1) ? p
: p
->in
.right
;
/* If argument to print/scan is of type... */ int argtype
;
/* ...and this length character is used... */ char lchar
;
/* ...and one of these is control char... */ char * cchars
;
/* ...then use this format with werror... */ char * werror
;
/* ...(where NULL means it's hunky dory)... */
** H&S says "%o" takes an unsigned argument;
** X3J11 says "%o" takes an int argument;
** we'll allow either here.
static struct entry pprintf
[] = {
CHAR
, '\0', "c", NULL
, /* this is deliberate */
INT
, '\0', "cdoxX", NULL
,
UNSIGNED
, '\0', "uoxX", NULL
,
CHAR
, '\0', "cdoxX", NULL
,
UCHAR
, '\0', "udoxX", NULL
, /* yes, d is okay */
SHORT
, '\0', "cdoxX", NULL
,
USHORT
, '\0', "uoxX", NULL
,
ENUMTY
, '\0', "duoxX", NULL
,
ULONG
, 'l', "uoxX", NULL
,
FLOAT
, '\0', "eEfgG", NULL
,
DOUBLE
, '\0', "eEfgG", NULL
,
PTR
|CHAR
, '\0', "s", NULL
,
** It allows %D, %O, and %U, which we deprecate.
** sizeof (char *) == sizeof (int) &&
** sizeof (int) == sizeof (long) &&
** sizeof (char *) == sizeof (int *)
** you can be lax--and we tolerate *some* laxness.
** g/lax/p to find lax table entries and code.
static char uppercase
[] = "deprecated upper-case control character (%c)";
static struct entry bprintf
[] = {
CHAR
, '\0', "c", NULL
, /* this is deliberate */
INT
, '\0', "cdoxX", NULL
,
INT
, '\0', "DO", uppercase
,
UNSIGNED
, '\0', "uoxX", NULL
,
UNSIGNED
, '\0', "UO", uppercase
,
CHAR
, '\0', "cdoxX", NULL
,
CHAR
, '\0', "DO", uppercase
,
UCHAR
, '\0', "duoxX", NULL
, /* yes, d is okay */
UCHAR
, '\0', "DUO", uppercase
,
SHORT
, '\0', "cdoxX", NULL
,
SHORT
, '\0', "DO", uppercase
,
USHORT
, '\0', "duoxX", NULL
, /* d okay on BSD */
USHORT
, '\0', "DUO", uppercase
,
ENUMTY
, '\0', "duoxX", NULL
,
ENUMTY
, '\0', "DUO", uppercase
,
LONG
, '\0', "DO", uppercase
,
ULONG
, '\0', "uoxX", lax
,
ULONG
, '\0', "UO", uppercase
,
ULONG
, 'l', "uoxX", NULL
,
UNSIGNED
, 'l', "uoxX", lax
,
FLOAT
, '\0', "eEfgG", NULL
,
DOUBLE
, '\0', "eEfgG", NULL
,
PTR
|CHAR
, '\0', "s", NULL
,
** Portable scanf. 'l' and 'h' are universally ignored preceding 'c' and 's',
** and 'h' is universally ignored preceding 'e' and 'f',
** but you won't find such cruft here.
static struct entry pscanf
[] = {
UNSIGNED
, '\0', "uox", NULL
,
USHORT
, 'h', "uox", NULL
,
FLOAT
, '\0', "ef", NULL
, /* BSD doesn't handle g */
** Berkeley scanf. An upper case letter equals an l plus the lower case char,
** but this is deprecated.
** Even though sizeof (int) == sizeof (long), we'll be picky here.
static struct entry bscanf
[] = {
UNSIGNED
, '\0', "uox", NULL
,
USHORT
, 'h', "uox", NULL
,
LONG
, '\0', "DOX", uppercase
,
ULONG
, '\0', "UOX", uppercase
,
DOUBLE
, '\0', "EF", uppercase
,
char * name
; /* such as "printf" */
int isscan
; /* scanf/printf */
int fmtarg
; /* number of format argument */
struct entry
* ptable
; /* portable checking table */
struct entry
* btable
; /* berkeley checking table */
"printf", 0, 1, pprintf
, bprintf
,
"fprintf", 0, 2, pprintf
, bprintf
,
"sprintf", 0, 2, pprintf
, bprintf
,
"scanf", 1, 1, pscanf
, bscanf
,
"fscanf", 1, 2, pscanf
, bscanf
,
"sscanf", 1, 2, pscanf
, bscanf
,
static char pwf
[] = "possible wild format";
static char pfacm
[] = "possible format/argument count mismatch";
register struct entry
* ep
;
for ( ; ep
->argtype
!= UNDEF
; ++ep
)
if (ep
->lchar
== lchar
&& strchr(ep
->cchars
, cchar
) != 0)
register struct symtab
* sp
;
register int i
, j
, isscan
;
register struct entry
* basep
;
register struct entry
* ep
;
register struct item
* ip
;
return NULL
; /* not a print/scan function */
else if (strcmp(ip
->name
, sp
->sname
) == 0)
return NULL
; /* handled in pass 2 */
tp
= ntharg(p
, i
, acount
);
if (tp
->in
.type
!= (PTR
|CHAR
))
return NULL
; /* handled in pass 2 */
if (tp
->in
.op
!= ICON
|| tp
->tn
.lval
!= 0)
return NULL
; /* can't check it */
for (j
= 1; j
<= subscr
; ++j
)
return NULL
; /* oh well. . . */
** cp now points to format string.
** For now, ALWAYS use "portable" table, rather than doing this:
** basep = pflag ? ip->ptable : ip->btable;
return (i
== acount
) ? NULL
: pfacm
;
return "wild trailing %% in format";
if (!suppressed
&& ++i
<= acount
) {
t
= ntharg(p
, i
, acount
)->in
.type
;
"%s argument is type (%s) rather than pointer (arg %d)",
ip
->name
, typestr(t
), i
);
int nspace
, ndash
, nplus
, nhash
;
nspace
= ndash
= nplus
= nhash
= 0;
if (nspace
> 1 || ndash
> 1 || nplus
> 1 || nhash
> 1)
return "wild repeated flag character in format";
t
= ntharg(p
, i
, acount
)->in
.type
;
** Width other than INT or UNSIGNED is suspect.
if (t
!= INT
&& t
!= UNSIGNED
) {
"field width argument is type (%s) rather than (int) (arg %d)",
} else while (isdigit(*cp
))
t
= ntharg(p
, i
, acount
)->in
.type
;
if (t
!= INT
&& t
!= UNSIGNED
) {
"precision argument is type (%s) rather than (int) (arg %d)",
} else while (isdigit(*cp
))
t
= ntharg(p
, i
, acount
)->in
.type
;
if (*cp
== 'h' || *cp
== 'l')
if ((cchar
= *cp
++) == '\0')
return (findlc(basep
, lchar
, cchar
) == NULL
) ?
if (!isscan
&& !pflag
&& ISPTR(t
) &&
strchr("douxX", cchar
) != 0)
continue; /* lax--printf("%d", (int *)) */
if (findlc(basep
, lchar
, cchar
) == NULL
)
} else for (ep
= basep
; ; ++ep
) {
if (ep
->argtype
== UNDEF
) { /* end of table */
ep
= findlc(basep
, lchar
, cchar
);
(void) sprintf(errbuf
, "%s: (%s) format, (%s) arg (arg %d)",
typestr(isscan
? (t
| PTR
) : t
), i
);
if (ep
->argtype
== t
&& ep
->lchar
== lchar
&&
strchr(ep
->cchars
, cchar
) != 0)
werror(ep
->werror
, cchar
);
return "possible unmatched '[' in format";
if ((cp
= subform(p
, sp
, acount
)) != NULL
)
cisreg(t
) TWORD t
; {return(1);} /* everyting is a register variable! */
fldty(p
) struct symtab
*p
; {
; /* all types are OK here... */
fldal(t
) unsigned t
; { /* field alignment... */
if( t
== ENUMTY
) return( ALCHAR
); /* this should be thought through better... */
if( ISPTR(t
) ){ /* really for the benefit of honeywell (and someday IBM) */
if( pflag
) uerror( "nonportable field type" );
else uerror( "illegal field type" );
while ((ch
= getopt(argc
,argv
,"C:D:I:U:LX:Pabchnpuvxz")) != EOF
)
case 'I': /* include path */
case 'X': /* debugging, done in first pass */
case 'P': /* debugging, done in second pass */
case 'v': /* unused arguments in functions */
case 'a': /* long to int assignment */
case 'b': /* unreached break statements */
case 'c': /* questionable casts */
case 'h': /* heuristics */
case 'n': /* standard library check */
case 'p': /* IBM & GCOS portability */
case 'u': /* 2nd pass: undefined or unused */
case 'x': /* unused externs */
case 'z': /* use of undefined structures */
fputs("usage: lint [-C lib] [-D def] [-I include] [-U undef] [-Labchnpuvx] file ...\n",stderr
);
if (!pflag
) { /* set sizes to sizes of target machine */
SZINT
= ALINT
= sizeof(int)*SZCHAR
;
SZFLOAT
= ALFLOAT
= sizeof(float)*SZCHAR
;
SZDOUBLE
= ALDOUBLE
= sizeof(double)*SZCHAR
;
SZLONG
= ALLONG
= sizeof(long)*SZCHAR
;
SZSHORT
= ALSHORT
= sizeof(short)*SZCHAR
;
SZPOINT
= ALPOINT
= sizeof(int *)*SZCHAR
;
/* now, fix some things up for various machines (I wish we had "alignof") */
ALLONG
= ALDOUBLE
= ALFLOAT
= ALINT
;
return(mainp1(argc
,argv
));
ctype( type
) unsigned type
; { /* are there any funny types? */
/* put out a common declaration */
if( stab
[i
].sclass
== STATIC
) outdef( &stab
[i
], LST
, USUAL
);
else outdef( &stab
[i
], libflag
?LIB
:LDC
, USUAL
);
isitfloat ( s
) char *s
; {
/* s is a character string;
if floating point is implemented, set dcon to the value of s */
fldcon( p
) register NODE
*p
; {
/* p is an assignment of a constant to a field */
/* check to see if the assignment is going to overflow, or otherwise cause trouble */
if( !hflag
& !pflag
) return;
s
= UPKFSZ(p
->in
.left
->tn
.rval
);
v
= p
->in
.right
->tn
.lval
;
switch( p
->in
.left
->in
.type
){
if( v
>=0 && (v
>>(s
-1))==0 ) return;
werror( "precision lost in assignment to (possibly sign-extended) field" );
if( v
<0 || (v
>>s
)!=0 ) werror( "precision lost in field assignment" );
outdef( p
, lty
, mode
) struct symtab
*p
; {
/* output a definition for the second pass */
/* if mode is > USUAL, it is the number of args */
else if( mode
== SVLINE
){
strncpy( rc
.l
.name
, exname(p
->sname
), LCHNM
);
if( mode
== DECTY
) t
= DECREF(t
);
astype( &rc
.l
.type
, p
->sizoff
);
rc
.l
.nargs
= (mode
>USUAL
) ? mode
: 0;
fwrite( (char *)&rc
, sizeof(rc
), 1, stdout
);
rc
.l
.name
= exname(p
->sname
);
fwrite( rc
.l
.name
, strlen(rc
.l
.name
)+1, 1, stdout
);